Skip to content

Extras

AppShell

Bit.BlazorUI.ExtrasAppLayoutAppContainerSafeArea

BitAppShell is the outermost element of an app. It insets the four edges of the screen by the device safe areas (notch, rounded corners, home indicator), makes room for the on-screen keyboard, and owns the one region the app scrolls in - so the header and footer stay put, only the middle moves, and a Modal, Panel, Dialog or Overlay inside it holds the right scroller on its own. That scroller can be driven from code, reports where it stands, pins to new content, keeps the reader's place across navigation and prints at full length.

Notes

Ships in the Bit.BlazorUI.Extras(opens in a new tab) nuget package (see the Optional steps of Getting started).

Put it in MainLayout around everything the app renders. It fills the room it is given, so either give html and body a height or set FullScreen. The examples below sit in fixed-height boxes and carry an Id, since the id of the scrolling container is derived from it.

The scrolling middle is a flex row: give the element holding the page width: 100%. The safe areas are only reported on a page whose viewport meta tag has viewport-fit=cover; they are 0 on desktop browsers. BitPullToRefresh and BitInfiniteScrolling target the shell with ScrollerSelector="#BitAppShell-container" (or the shell's MainContainerId).

While nothing has focus, the arrows, Page Up/Down, Home/End and Space scroll the page's shell, as they would scroll the document of a page without one.

Usage

Every example is live. Open its code to see exactly what produced the component running underneath.

Basic

Everything inside the shell lands in its scrolling middle, so a sticky header stays put while the rows move.


Header
Row 1
Row 2
Row 3
Row 4
Row 5
Row 6
Row 7
Row 8
Row 9
Row 10
Row 11
Row 12

Safe area insets

Four bars keep the content off the notch and the home indicator. Desktop browsers report no safe areas, so this shell is handed a phone's through the --bit-AppShell-safe-area-* variables, which is also how a hybrid app maps the insets its native side measured. They inherit, so they are set on the box around it.

NoInsets removes all four for an edge-to-edge layout; NoTopInset, NoBottomInset, NoStartInset and NoEndInset remove one (start and end follow the reading direction). StableInsets sizes the bars from the device maximums, so the layout does not move as browser chrome slides in and out (Chromium 135+).



Row 1
Row 2
Row 3
Row 4
Row 5
Row 6
Row 7
Row 8
Row 9
Row 10
Row 11
Row 12

Keyboard inset

On mobile, the on-screen keyboard covers the bottom of the page without resizing it. AvoidKeyboard takes the covered height off the scrolling middle, so a bottom bar rides up above the keyboard. The height is published as --bit-ash-keyboard-inset, the root carries data-bit-ash-keyboard while the keyboard is up, and OnKeyboardInsetChanged reports it to C#. Nothing happens on desktop browsers.


Keyboard inset: 0 px

Row 1
Row 2
Row 3
Row 4
Row 5
Row 6
Row 7
Row 8
Row 9
Row 10

Scrolling from code

GoToTop, GoToBottom, ScrollTo (a null axis stays put), ScrollBy and ScrollToElement move the shell; GetScrollOffset reads where it stands.

ScrollBehavior animates every move the reader does not make by hand - these methods, fragment navigation, focus scrolling. It defaults to Smooth, which reduced motion turns off (use the ForceAnimation toggle at the top of the page to override). Each method also takes its own behavior.




-

Row 1
Row 2
Row 3
Row 4
Row 5
Row 6
Row 7
Row 8
Row 9
Row 10
Row 11
Row 12
Row 13
Row 14
Row 15
Row 16
Row 17
Row 18
Row 19
Row 20 (the ScrollToElement target)
Row 21
Row 22
Row 23
Row 24
Row 25
Row 26
Row 27
Row 28
Row 29
Row 30

Scroll events & state

OnScroll reports the position and direction, OnScrollStart / OnScrollEnd bracket a gesture, and OnReachedTop / Bottom / Left / Right fire once per arrival (ReachOffset sets how near counts). Nothing is listened to until a callback is handled; ScrollThrottle caps how often OnScroll fires.

TrackScrollState marks the root with data-bit-ash-scrolled and data-bit-ash-scroll-direction (up / down), so chrome reacts in CSS with no round trip: this header lifts with a shadow once scrolled and slides away while scrolling down.


Top: 0 px (0%)
Direction: -
Phase: idle
Reached: -

Header
Row 1
Row 2
Row 3
Row 4
Row 5
Row 6
Row 7
Row 8
Row 9
Row 10
Row 11
Row 12
Row 13
Row 14
Row 15
Row 16
Row 17
Row 18
Row 19
Row 20
Row 21
Row 22
Row 23
Row 24
Row 25
Row 26
Row 27
Row 28
Row 29
Row 30
Row 31
Row 32
Row 33
Row 34
Row 35
Row 36
Row 37
Row 38
Row 39
Row 40

Overflow & overscroll

OverflowX / OverflowY set each axis; Hidden keeps one too-wide element from making the whole app scroll sideways. NoScroll stops the reader's scrolling on both axes, while the methods still move it. Gutter reserves the scrollbar's room, so pages of different lengths do not shift.

Overscroll decides what happens at an edge: None (the default) stops scroll chaining and the bounce / pull-to-refresh, Contain only stops the chaining, Auto lets the scroll carry on into this page.



Overscroll



A row wider than the shell
Row 1
Row 2
Row 3
Row 4
Row 5
Row 6
Row 7
Row 8
Row 9
Row 10
Row 11
Row 12
Row 13
Row 14
Row 15
Row 16
Row 17
Row 18
Row 19
Row 20

Scroll padding

ScrollPadding keeps what is scrolled into view - by ScrollToElement, a fragment link or keyboard focus - out from under a sticky header (WCAG 2.4.11, focus not obscured). Any CSS length works, insets included: calc(var(--bit-ash-inset-top) + 3rem) 0 0 0.




A sticky header
Row 1
Row 2
Row 3
Row 4
Row 5
Row 6
Row 7
Row 8
Row 9
Row 10
Row 11
Row 12
Row 13
Row 14
Row 15 (the target)
Row 16
Row 17
Row 18
Row 19
Row 20
Row 21
Row 22
Row 23
Row 24
Row 25
Row 26
Row 27
Row 28
Row 29
Row 30

Endless content

AutoScroll keeps a chat or a log pinned to its newest content, but only while the reader is at the end (AutoScrollThreshold sets how near counts). PreserveScroll keeps the reader's place when older content arrives above it - pair it with OnReachedTop. Refresh re-measures after changes the shell cannot see, such as a web font loading.




Message 1
Message 2
Message 3
Message 4
Message 5
Message 6
Message 7
Message 8
Message 9
Message 10
Message 11
Message 12

Navigation

The shell's scroller does not move on navigation by itself. AutoGoToTop opens each page at its top. PersistScroll remembers where each url was left (per tab, in session storage) and puts the reader back there, retrying while the page's content loads; another page with nothing stored opens at its top, while a url that only changes its query (a filter, a search box) is left where it stands. It wins over AutoGoToTop, and ClearPersistedScroll forgets one url or all of them (e.g. on sign-out). In-page anchor links are left alone by both.

ScrollRestoration picks which navigations are restored: Url (the default) every one, like the tabs of a mobile app; History only back and forward, opening links at the top as a browser does.


Both act on navigation between pages, which a shell inside this page cannot show - see the markup.

Cascading values

Values (a list of BitCascadingValue) and ValueList cascade values - the signed-in user, a tenant - to every page without a chain of CascadingValues. Values win over ValueList for the same type and name, and changing a value refreshes its readers.


Cascaded by type: Saleh Yusefnejad (Developer)
Cascaded by name: bit platform

Cascading parameters

BitParams with a BitAppShellParams sets defaults for every shell under it; a shell's own value wins (the second one keeps its bottom inset).


All cascaded
Own NoBottomInset

Style & Class

Style and Class reach the root; Styles and Classes reach each part: Root, Top, Center, Left, Main, Right and Bottom.


Row 1
Row 2
Row 3
Row 4
Row 5
Row 6
Row 7
Row 8
Row 9
Row 10
Row 11
Row 12

RTL

With Dir set to Rtl the shell lays out right to left, so the start bar (wider here) is on the right. Left to the device, each side bar is still sized from the safe area of its own physical edge.


سطر 1
سطر 2
سطر 3
سطر 4
سطر 5
سطر 6
سطر 7
سطر 8
سطر 9
سطر 10
سطر 11
سطر 12

CSS variables

The public custom properties this component reads off its root, for what no parameter covers.

Every variable is read with a fallback and never declared by the component, so it inherits like any other custom property: set one on :root (or in a [bit-theme] block) to restyle every instance, on any ancestor to restyle the ones inside it, or on the Style of one instance to restyle that one alone. Leave a variable unset and the component falls back to the theme token beside it.

BitAppShell CSS variables

Name Default value Description
--bit-AppShell-background var(--bit-clr-bg-pri) Background of the shell, and of the four inset bars unless they are given their own.
--bit-AppShell-color var(--bit-clr-fg-pri) Text color the content inherits, paired with the background. Set it to inherit to keep the host page's own.
--bit-AppShell-inset-background --bit-AppShell-background Background of the four inset bars.
--bit-AppShell-inset-top-background --bit-AppShell-inset-background Background of the top bar, behind the status bar - commonly the color of the header below it.
--bit-AppShell-inset-bottom-background --bit-AppShell-inset-background Background of the bottom bar, behind the home indicator.
--bit-AppShell-inset-start-background --bit-AppShell-inset-background Background of the leading side bar (left in LTR, right in RTL).
--bit-AppShell-inset-end-background --bit-AppShell-inset-background Background of the trailing side bar (right in LTR, left in RTL).
--bit-AppShell-safe-area-top env(safe-area-inset-top) How far the top edge is inset. Set it to map the insets a native host measured, or to keep a minimum with max(). StableInsets defaults it to the device maximum; NoInsets and NoTopInset win over it.
--bit-AppShell-safe-area-bottom env(safe-area-inset-bottom) How far the bottom edge is inset. NoInsets and NoBottomInset win over it.
--bit-AppShell-safe-area-start the inline-start env() inset How far the leading edge is inset. NoInsets and NoStartInset win over it.
--bit-AppShell-safe-area-end the inline-end env() inset How far the trailing edge is inset. NoInsets and NoEndInset win over it.

API

Every parameter, public member, sub-class and enum this component exposes.

BitAppShell parameters

Name Type Default value Description
AutoGoToTop bool false Enables auto-scroll to the top of the main container on navigation. A navigation that only changes the fragment of the url (an in-page anchor) is left alone. PersistScroll takes precedence over it.
AutoScroll bool false Keeps the main container pinned to the end of its content as the content grows, for as long as the reader left it standing at the end.
AutoScrollThreshold int 0 How near the end of the content (in pixels) the main container has to have been left for AutoScroll to keep pinning it there.
AvoidKeyboard bool false Takes the height of the on-screen keyboard off the scrolling area while it is open, publishes it on the root as the --bit-ash-keyboard-inset CSS variable and marks the root with the data-bit-ash-keyboard attribute. A focused element the shorter middle leaves below its bottom edge is scrolled back into view. It measures 0 wherever the browser shrinks the layout viewport itself.
ChildContent RenderFragment? null The content of the app shell. It is rendered inside the main (scrolling) container.
Classes BitAppShellClassStyles? null Custom CSS classes for different parts of the app shell.
FullScreen bool false Pins the app shell to the four edges of the screen, so it fills the window whatever height the page around it has - which is what saves the host page from carrying a height of its own down through html and body.
Gutter BitScrollbarGutter? null Reserves the room the scrollbar of the main container takes, whether or not there is anything left to scroll, so the layout does not shift between a page that scrolls and a page that does not.
NoBottomInset bool false Removes the bottom safe area inset of the app shell, leaving the other three where they are.
NoEndInset bool false Removes the trailing side safe area inset of the app shell - the right of a left-to-right shell - leaving the other three where they are.
NoInsets bool false Removes the safe area insets, so the four edges of the app shell are not inset at all and the content fills the whole screen.
NoScroll bool false Prevents the reader from scrolling the main container at all; the content that overflows is clipped. The scrolling methods of the component still move it.
NoStartInset bool false Removes the leading side safe area inset of the app shell - the left of a left-to-right shell - leaving the other three where they are.
NoTopInset bool false Removes the top safe area inset of the app shell, leaving the other three where they are.
OnKeyboardInsetChanged EventCallback<double> Callback for how much of the app shell the on-screen keyboard covers, in pixels, raised as that changes and with 0 as it closes. Only a shell with AvoidKeyboard set measures it at all.
OnReachedBottom EventCallback Callback for when the main container reaches the bottom of its content, raised once per arrival rather than on every frame that stays there.
OnReachedLeft EventCallback Callback for when the main container reaches the visual left edge of its content, which is the same edge whichever way the shell reads.
OnReachedRight EventCallback Callback for when the main container reaches the visual right edge of its content.
OnReachedTop EventCallback Callback for when the main container reaches the top of its content.
OnScroll EventCallback<BitScrollOffset> Callback for the scroll position of the main container, raised as it is scrolled. Nothing is measured or reported until one of the scroll callbacks is handled.
OnScrollEnd EventCallback<BitScrollOffset> Callback for when a scroll of the main container comes to a stop.
OnScrollStart EventCallback<BitScrollOffset> Callback for when a scroll of the main container begins.
OverflowX BitOverflow? null What the main container does with content that overflows it sideways. Hidden clips it instead of offering it, and NoScroll wins over both axes.
OverflowY BitOverflow? null What the main container does with content that overflows it downwards. See OverflowX.
Overscroll BitOverscroll? null Determines what happens when the main container is scrolled past its edge. It defaults to None: no scroll chaining out of the shell and no pull-to-refresh or rubber-banding.
PersistScroll bool false Persists scroll position of the main container per url in session storage and restores it on navigation; another page with nothing stored opens at its top, while a navigation that only changes the query (a filter, a search box) or the fragment is left where it stands. One shell per page owns the store, so it is not part of BitAppShellParams.
PreserveScroll bool false Keeps the place of the reader when content is added above what they are looking at, which is what an endless list growing upwards needs.
ReachOffset int 0 How near an edge (in pixels) counts as having reached it, for OnReachedTop and OnReachedBottom.
ScrollBehavior BitScrollBehavior? null The scroll behavior of the main container, which decides how every move the reader does not make by hand is animated. It defaults to Smooth, and is taken back off under the reduced motion preference.
ScrollPadding string? null The room the main container keeps between its edges and anything scrolled into view inside it, as any CSS length - which is what keeps a header stuck to the top of the shell from covering what was just scrolled to.
ScrollRestoration BitAppShellScrollRestoration BitAppShellScrollRestoration.Url Which navigations PersistScroll restores: Url restores every navigation to a url left scrolled (app tabs); History only the back and forward buttons, opening every other navigation at its top as a browser does.
ScrollThrottle int 0 The shortest interval (in milliseconds) between two OnScroll reports. The default of 0 reports once per animation frame.
StableInsets bool false Sizes the four inset bars from the largest safe areas the device can ask for rather than from the ones it is asking for right now, so the layout is not relaid out as the browser slides its own chrome in and out.
Styles BitAppShellClassStyles? null Custom CSS styles for different parts of the app shell.
TrackScrollState bool false Marks the root with data-bit-ash-scrolled while the main container is away from its top, and with data-bit-ash-scroll-direction (up or down) for the way it was last scrolled, so a header can lift or hide itself in CSS alone.
ValueList BitCascadingValueList? null The cascading value list to be provided for the children of the app shell. Its values are provided before (so they can be overridden by) the ones of the Values parameter.
Values IEnumerable<BitCascadingValue>? null The cascading values to be provided for the children of the app shell.

BitAppShell public members

Name Type Default value Description
ClearPersistedScroll Func<string?, Task> Forgets every scroll position PersistScroll has kept, for the pages of this app shell and of any other - or, given a url, only the position kept for that one page.
Container const string "BitAppShell.Container" The name the app shell cascades the element of its main container under, which is what a Modal, a Panel, a Dialog or an Overlay inside the shell reads to hold the right scroller.
ContainerId const string "BitAppShell-container" The id the main container carries when the app shell has no Id of its own.
ContainerRef ElementReference? null The element reference to the main container of the app shell.
GetScrollOffset Func<Task<BitScrollOffset?>> Reads where the main container currently stands, measured in the browser.
GoToBottom Func<BitScrollBehavior?, Task> Scrolls the main container to the bottom of its content.
GoToTop Func<BitScrollBehavior?, Task> Scrolls the main container to top.
MainContainerId string The id of the main container element of this app shell: ContainerId, or the Id of the shell with "-container" after it.
Refresh Func<Task> Re-measures the main container and reports whatever has changed since it was last measured - for the changes neither its own size nor its content announce, such as a web font that has finished loading.
ScrollBy Func<double, double, BitScrollBehavior?, Task> Scrolls the main container by an amount, from wherever it currently stands.
ScrollTo Func<double?, double?, BitScrollBehavior?, Task> Scrolls the main container to a position. A null axis is left where it stands.
ScrollToElement Func<string, double, bool, BitScrollAlignment, BitScrollBehavior?, Task> Brings an element inside the main container into view by scrolling the container itself rather than every scroller the page sits in.

BitComponentBase parameters

Name Type Default value Description
AriaLabel string? null Gets or sets the accessible label for the component, used by assistive technologies.
Class string? null Gets or sets the CSS class name(s) to apply to the rendered element.
Dir BitDir? null Gets or sets the text directionality for the component's content.
Disabled bool false Gets or sets a value indicating whether the component is disabled and cannot respond to user interaction.
ForceAnimation bool false Gets or sets a value indicating whether the component's animations play at their full duration even when reduced motion is requested.
HtmlAttributes Dictionary<string, object> new Dictionary<string, object>() Captures additional HTML attributes to be applied to the rendered element, in addition to the component's parameters.
Id string? null Gets or sets the unique identifier for the component's root element.
Style string? null Gets or sets the CSS style string to apply to the rendered element.
TabIndex string? null Gets or sets the tab order index for the component when navigating with the keyboard.
Visibility BitVisibility BitVisibility.Visible Gets or sets the visibility state (visible, hidden, or collapsed) of the component.

BitComponentBase public members

Name Type Default value Description
UniqueId Guid Guid.NewGuid() Gets the readonly unique identifier for the component's root element, assigned when the component instance is constructed.
RootElement ElementReference Gets the reference to the root HTML element associated with this component.

BitCascadingValueList properties

A List<BitCascadingValue> with typed helpers for building and revising a set of cascading values; its collection initializer takes { value, name } pairs. These are the members the shell's ValueList is usually built with; the BitCascadingValueProvider page documents all of them.

Name Type Default value Description
Add<T>(T value, string? name = null, bool isFixed = false, bool enabled = true) void Adds a typed BitCascadingValue to the list, cascading the value as the static type of T.
Add(BitCascadingValue? value) void Adds an already created BitCascadingValue to the list. A null item is ignored.
Set<T>(T value, string? name = null, bool isFixed = false, bool enabled = true) void Replaces every entry of the static type of T and the given name with one new entry, in the place of the first, or appends it when there is none.

BitCascadingValue properties

One value to cascade: what is cascaded, as which type, under which name, and whether it is fixed or provided at all. Bare values and (value, name) tuples of the common primitive, date, string and BitDir types convert to it implicitly. These are the members the shell's Values are usually built with; the BitCascadingValueProvider page documents all of them, including the factories and the typed BitCascadingValue<T>.

Name Type Default value Description
Value object? null The value to be provided. Assigning a value not assignable to ValueType throws an ArgumentException; assigning a different value refreshes the consumers.
Name string? null The optional name of the cascading value, matched case-insensitively; an empty or white-space name means no name.
IsFixed bool false Marks a value that never changes, so its consumers are not subscribed for change notifications.
Enabled bool true Whether the value is provided at all. A disabled value is skipped as if it had never been added, so an outer or root-level value of the same type and name shows through.

BitAppShellClassStyles properties

Name Type Default value Description
Root string? null Custom CSS classes/styles for the root of the BitAppShell.
Top string? null Custom CSS classes/styles for the top inset bar of the BitAppShell.
Center string? null Custom CSS classes/styles for the center row of the BitAppShell, which holds the two side inset bars and the main container.
Left string? null Custom CSS classes/styles for the leading side inset bar of the BitAppShell.
Main string? null Custom CSS classes/styles for the main (scrolling) container of the BitAppShell.
Right string? null Custom CSS classes/styles for the trailing side inset bar of the BitAppShell.
Bottom string? null Custom CSS classes/styles for the bottom inset bar of the BitAppShell.

BitScrollOffset properties

Where the main container of the app shell stands, as measured in the browser. Everything is in CSS pixels; the members derived from the measured ones cost nothing to read.

Name Type Default value Description
Left double 0 The raw scrollLeft of the container.
Top double 0 How far the content has been scrolled down.
ScrollWidth double 0 The full width of the content, including the part scrolled out of sight.
ScrollHeight double 0 The full height of the content, including the part scrolled out of sight.
ClientWidth double 0 The width of the visible area, without its scrollbar.
ClientHeight double 0 The height of the visible area, without its scrollbar.
Rtl bool false Whether the container was laid out right to left when it was measured.
DeltaLeft / DeltaTop double 0 How far the container has moved since the position before this one was reported. Only the OnScroll reports carry them.
OffsetLeft double The distance from the visual left edge, which is Left made positive and direction independent.
MaxLeft / MaxTop double The largest offset each axis can reach, which is how much of the content is out of sight.
ScrollableX / ScrollableY bool Whether there is anything to scroll along each axis at all.
AtLeft / AtRight / AtTop / AtBottom bool Whether the container is standing at each edge, within a pixel of slack.
PercentX / PercentY double How far the container has been scrolled along each axis, from 0 to 1.
ScrollingUp / ScrollingDown / ScrollingLeft / ScrollingRight bool Which way the move this report carries went, derived from the deltas - which is what a header that folds away on the way down reads.

BitScrollBehavior enum

Name Value Description
Smooth 0 Scrolling should animate smoothly.
Instant 1 Scrolling should happen instantly in a single jump.
Auto 2 Scroll behavior is determined by the computed value of scroll-behavior.

BitAppShellScrollRestoration enum

Name Value Description
Url 0 Every navigation to a url that was left scrolled is restored, however it was navigated to - the tabs of a mobile app, each keeping its own place.
History 1 Only the browser's back and forward navigations are restored; every other navigation opens the page at its top, as a browser does.

BitOverflow enum

Name Value Description
Auto 0 A scrollbar is offered along that axis when the content overflows, and nothing is shown when it does not.
Hidden 1 The overflow is clipped and no scrollbar is offered, though the axis can still be moved through the scrolling methods of the component.
Scroll 2 A scrollbar is always shown along that axis, whether or not there is anything to scroll.
Visible 3 The overflow is neither clipped nor scrollable, so it is painted outside the container.

BitScrollbarGutter enum

Name Value Description
Auto 0 The initial value: a classic scrollbar takes its room only while there is something to scroll, and an overlay scrollbar takes none at all.
Stable 1 The room is reserved whether or not there is anything to scroll, so the layout does not shift as pages of different lengths follow one another.
BothEdges 2 Like Stable, with the same room reserved on the opposite edge as well, so the content stays centered.

BitOverscroll enum

Name Value Description
Auto 0 The scroll carries on into the nearest scrolling ancestor, and the platform's own overscroll affordance is kept.
Contain 1 The scroll stops at the edge instead of carrying on into the page behind it, while the platform's own overscroll affordance is kept.
None 2 Like Contain, and the platform's own overscroll affordance is suppressed as well, so the container neither bounces nor triggers a pull to refresh.

BitScrollAlignment enum

Name Value Description
Start 0 The element is brought to the start of the container.
Center 1 The element is centered in the container along both axes.
End 2 The element is brought to the end of the container.
Nearest 3 The container moves as little as it can.

BitVisibility enum

Name Value Description
Visible 0 The content of the component is visible.
Hidden 1 The content of the component is hidden, but the space it takes on the page remains (visibility:hidden).
Collapsed 2 The component is hidden (display:none).

BitDir enum

Name Value Description
Ltr 0 Ltr (left to right) is to be used for languages that are written from the left to the right (like English).
Rtl 1 Rtl (right to left) is to be used for languages that are written from the right to the left (like Arabic).
Auto 2 Auto lets the user agent decide. It uses a basic algorithm as it parses the characters inside the element until it finds a character with a strong directionality, then applies that directionality to the whole element.

Feedback

Found a mistake, a gap, or something that could be clearer? Every page and every component is one click from its source.