Screen Transition

Screen Transition

Direction-aware animated screen switcher for shell-based navigation. Supports Tab (fade), Push (slide right), and Pop (slide left) — the three primitives of mobile-style navigation.

Interactive demo

A shell with 3 tabs and a push/pop flow. Tab-switching fades; tapping Settings pushes a detail screen; the back button pops back.

Good morning 👋

Welcome to the Home tab.

🍎 Fruits
🥑 Veggies
🥩 Proteins
🧁 Treats

Direction reference

Each direction maps to a real navigation gesture — use them semantically for the best UX.

Tab
Fade in

Switching between sibling tabs. The tab bar stays static; only the content area fades.

Push
Slide from right

Drilling into a detail screen. Mirrors iOS/Android push navigation.

Pop
Slide from left

Returning to a parent screen. Pair with a back button to complete the gesture.

Usage in a shell component

Set Direction before changing Key — both happen in the same render cycle so no extra StateHasChanged is needed.

// In the parent shell component:
private ScreenTransitionDirection _dir;
private Screen _current;

private void NavigateTo(Screen screen)
{
    _dir = screen is Screen.Home or Screen.Menu
        ? ScreenTransitionDirection.Tab
        : ScreenTransitionDirection.Push;
    _current = screen;    // Key changes → animation fires
}

private void GoBack()
{
    _dir = ScreenTransitionDirection.Pop;
    _current = _previousScreen;
}

Auto-detecting direction from URL depth

When sub-components trigger navigation directly via NavigationManager, detect direction in OnLocationChanged by comparing URL segment depth.

// When sub-components call Nav.NavigateTo() directly,
// detect direction in OnLocationChanged:

private string _fromPath = string.Empty;
private string _backTarget = string.Empty;
private bool _isGoingBack = false;

protected override void OnInitialized()
{
    _fromPath = Nav.ToBaseRelativePath(Nav.Uri).ToLower().TrimEnd('/');
    Nav.LocationChanged += OnLocationChanged;
}

private void OnLocationChanged(object? sender, LocationChangedEventArgs e)
{
    var newPath = Nav.ToBaseRelativePath(e.Location).ToLower().TrimEnd('/');

    if (_isGoingBack)
    {
        _transitionDirection = ScreenTransitionDirection.Pop;
        _isGoingBack = false;
    }
    else if (IsRootTab(newPath))
    {
        _transitionDirection = ScreenTransitionDirection.Tab;
        _backTarget = string.Empty;
    }
    else
    {
        var fromDepth = _fromPath.Split('/').Length;
        var newDepth  = newPath.Split('/').Length;
        if (newDepth > fromDepth) { _transitionDirection = ScreenTransitionDirection.Push; _backTarget = _fromPath; }
        else if (newDepth < fromDepth) { _transitionDirection = ScreenTransitionDirection.Pop; }
        else { _transitionDirection = ScreenTransitionDirection.Tab; }
    }

    _fromPath = newPath;
    InvokeAsync(StateHasChanged);
}

private void GoBack()
{
    if (!string.IsNullOrEmpty(_backTarget))
    {
        _isGoingBack = true;
        Nav.NavigateTo(_backTarget);
    }
}

Parameters

Parameter Type Default Description
Keyobject?—Change this to trigger the transition (enum, string, or int)
DirectionScreenTransitionDirectionNoneTab, Push, Pop, or None (no animation)
Durationdouble0.28Animation duration in seconds
SlideDistancedouble40Slide distance in pixels for Push/Pop
Classstring?—CSS classes applied to the wrapper element

Reconnecting...

Attempting to rejoin the server

Connection Lost

Retrying in seconds

Connection Failed

Failed to rejoin the server.
Please retry or reload the page.

Session Paused

The session has been paused by the server

Resume Failed

Failed to resume the session.
Please reload the page.