History
Drive the browser's session history from C#: move back and forward, push and replace entries with attached state, control scroll restoration and react to popstate.
@inject Bit.Butil.History historyMDN reference
GetLength reports how many entries the session history holds, including the current page. GetState returns the state object attached to the active entry, with a generic overload for strongly-typed deserialization.
int length = await history.GetLength();
object state = await history.GetState();
var typed = await history.GetState<MyState>();
public record MyState(int Step, string Name);PushState adds a new history entry with an optional state object and same-origin URL, without reloading the page. ReplaceState swaps the current entry in place - the standard tool for keeping the address bar in sync with client-side UI state.
await history.PushState(new { step = 2 }, "history?step=2");
await history.ReplaceState(new { step = 2, revised = true }, "history?step=2b");
// pressing Back now raises popstate with the previous state objectWatch the address bar - both calls change the URL without a page load.
popstate fires whenever the active history entry changes through user navigation (Back, Forward or Go), delivering the state object of the entry that became active. SubscribePopState returns a disposable subscription; AddPopState returns a Guid you can pass to RemovePopState.
ButilSubscription sub = await history.SubscribePopState(
state => Console.WriteLine($"popped: {state}"));
// alternative, id-based lifecycle:
Guid id = await history.AddPopState(state => { /* ... */ });
await history.RemovePopState(id);
// or drop everything this instance registered:
await history.RemoveAllPopStates();Subscribe, push a couple of entries above, then use the browser Back button.
Controls whether the browser restores the scroll position automatically when the user navigates through history. Set it to Manual when your app manages scroll itself, for example in virtualized lists.
ScrollRestoration current = await history.GetScrollRestoration();
await history.SetScrollRestoration(ScrollRestoration.Manual);
await history.SetScrollRestoration(ScrollRestoration.Auto);GoBack, GoForward and Go perform real history navigations -
the demo buttons above can move you away from this page (use the browser's Forward button to return).
Go(0) or Go() reloads the current page entirely.
PushState and ReplaceState must be same-origin with the
current page, otherwise the browser throws a security exception. The state object must be serializable.
API reference
Task<int> GetLength()Task<ScrollRestoration> GetScrollRestoration()Task SetScrollRestoration(ScrollRestoration value)Task<object> GetState()Task<T?> GetState<T>()Task GoBack()Task GoForward()Task Go(int? delta = null)Task PushState(object? state = null, string? url = null)Task ReplaceState(object? state = null, string? url = null)ValueTask<Guid> AddPopState(Action<object> handler)ValueTask<ButilSubscription> SubscribePopState(Action<object> handler)ValueTask RemovePopState(Guid id)ValueTask RemoveAllPopStates()ValueTask DisposeAsync()