Skip to content

Surfaces

Panel

Bit.BlazorUIDrawerSidebarOffcanvas

Panel is an overlay surface that slides in from an edge of the screen to host supplementary content - a form, a filter, a set of details, a navigation menu - without taking the user away from the page behind it. It slides in from any of the four edges, is sized along the axis it slides on, scrolls whatever it cannot fit, dims the page or leaves it usable, holds the page still while it is open, takes the keyboard over and hands it back, and is dismissed by a click on the overlay, the Escape key or a swipe of the finger - each of which it can be asked to refuse.

Usage

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

Basic

IsOpen is what shows and hides the panel, and binding to it is all a panel needs: the panel writes the value back when it dismisses itself, so the flag stays right whichever side closed it. The panel slides in from the end of the screen by default, sizes itself to its own content and scrolls whatever will not fit, covers the page without dimming it, and is dismissed by a click on the page behind it, the Escape key or a swipe towards the edge it came from.

The panel is also driveable through a reference to it: Open, Close and Toggle do what binding the flag would, from code that has no flag of its own.

ShowCloseButton puts a close button at the edge the panel slid in from, which is what a panel whose ways out have been taken away - a Blocking or a Modeless one - needs to be closable with the pointer at all. It names itself "Close" to a screen reader unless CloseButtonTitle says otherwise, and CloseIconName replaces the glyph in it.

Header and footer

A panel given a Header, a Footer or a ShowCloseButton builds the chrome that goes with them: a header row at the edge it slid in from, a body that takes the scrolling, and a footer at the far edge. The two parts around the body stay put however far the content between them is scrolled, which is what a panel whose actions have to stay reachable needs. A panel given none of the three is the plain surface of the section above, and its content fills it however it likes.

HeaderText and FooterText are the shorthands for the header and the footer that are nothing but a line of text, and the templates take precedence over them. Body is the content that reads right beside them - it is the same slot as ChildContent, named for what it becomes here, and it takes precedence when both are given.

The header also names the panel: a screen reader reads it out when the panel opens, without TitleAriaId having to point anywhere.

Position and size

Position is the edge the panel slides in from. Start and End are the logical edges, so they follow the direction of the panel and swap over in right-to-left, while Top and Bottom are the same edges everywhere.

Size is the size of the panel in pixels along the axis it slides on - the width of a panel at the start or the end, the height of one at the top or the bottom. Leaving it unset sizes the panel to its own content, and either way a strip of the page stays visible beside it. FullSize gives up that strip and takes the whole screen, which is what a panel holding a page of its own needs on a small screen.

Overlay and dismissal

A panel covers the page with an overlay that takes the clicks meant for what is behind it, and a click on that overlay dismisses the panel. Blocking keeps the overlay and takes away the dismissal, for a panel whose content has to be completed or cancelled through the panel itself, and OnOverlayClick still reports the click - which is how a blocking panel can draw attention to itself instead of closing.

That overlay is a transparent catcher of clicks by default, so the page behind it is still read at full strength. ModeFull gives it a background of its own, which is what a panel that takes the work over rather than sitting beside it wants: the page underneath recedes and the panel reads as the thing to deal with.

Modeless leaves the page its own clicks by rendering no overlay at all, so the panel sits alongside the work rather than instead of it. NoDismissOnEscape takes the Escape key away from a panel that is only meant to be closed by its own content, and OnEscapeKeyDown still reports the key the way OnOverlayClick reports the click, so a panel that turns the Escape down can answer it on terms of its own. OnDismiss is called for every one of those closings - the overlay, the Escape key, a swipe, the Close and Toggle methods and the flag being set from the outside - so it is the one place a panel has to clean up in.

Dismissed 0 times, last reason reported by OnDismissing: -

Refusing a dismissal

OnDismissing is called before the panel closes and is allowed to refuse the closing: set Cancel on the arguments it is handed and the panel stays where it is. It is awaited, so the answer can come from work of its own - a confirmation, a save, a look at what the user has typed so far.

Its Reason tells the closings apart: a click on the Overlay, the Escape key, a Swipe, or a Programmatic call to Close or Toggle. That is what lets a panel refuse the stray gesture that would throw away a half-filled form while still letting through the Close its own content asked for. The IsOpen flag being set from the outside has already happened by the time the panel sees it, so it never passes through here.

Last attempt: -, refused: False

Focus and the keyboard

A panel that opens takes the keyboard with it: the focus moves to the first focusable element in it - or to the element marked data-autofocus, for the panels whose first one is not the one worth starting at - Tab and Shift+Tab cycle inside it instead of running on into the page behind it, and closing the panel hands the focus back to whatever opened it. NoAutoFocus leaves the focus where it is, NoFocusTrap lets the keyboard walk out of the panel, and NoRestoreFocus leaves the focus wherever the panel left it instead of handing it back - for the panels whose closing is meant to move the keyboard on somewhere else. A Modeless panel never traps the focus, since the page behind it is meant to be reached. Escape reaches the panel from wherever the keyboard is inside it, so a panel that never took the keyboard over is also one Escape does not reach until the user has tabbed or clicked into it.

The panel reports itself to a screen reader as a dialog, which needs a name: give it one with AriaLabel, or point TitleAriaId at the heading the panel already shows. SubtitleAriaId points at what describes it, and IsAlert reports it as an alert dialog instead, for a panel carrying something the user has to deal with before carrying on.

Role takes over from that dialog altogether, for the panel that is not one: a Modeless panel left beside the page is better announced as a complementary or a region, since a screen reader tells the user a dialog is something to deal with and leave.

Page scrolling

A panel that covers the page holds it still while it is open: a page that carried on scrolling behind the panel would move what the user is coming back to out from under them. The scrollbar comes back when the panel closes - including when the panel is taken off the page while it is still open, so a navigation away from it never leaves the page stuck - and the room the scrollbar took is added back as padding while it is held, so nothing shifts sideways. The holds are counted: two panels open at once both hold the page, and it is handed back when the last of them closes, not the first.

ScrollerSelector names the element that is held, for the layouts that scroll something other than the document, and ScrollerElement hands one over directly where no selector reaches it. A panel inside a BitAppShell holds the shell's scroller without being told to, since the shell cascades it: the body of such a page never scrolls, so holding it would hold nothing.

NoScrollLock gives that up, for the panel that is meant to leave the page moving. A Modeless panel never holds the page in the first place. A panel that leaves the page scrolling still covers it with an overlay, and that layer is fixed to the viewport - so the wheel and the touch drag it catches are handed on to the scroller the panel names, and the page moves under the gesture the way it would with no panel over it. Anything inside the panel that scrolls itself takes its own gestures first.

AutoToggleScroll is the other way round: the panel takes the overflow off the scroller itself instead of taking the counted hold, and the room that gave back is what an AbsolutePosition panel is pushed down by so that it stays where the eye left it. The two never both apply - a panel doing its own scroll handling stands the hold down.

The panel scrolls its own content whenever there is more of it than the panel is allowed to take, and that scrolling stops at the panel: reaching the end of it does not carry on into the page underneath. Holding the page still is about the wheel that never reaches the panel at all.

Swipe to dismiss

Dragging the panel towards the edge it slid in from follows the pointer, and letting go past a quarter of the size of the panel dismisses it. SwipeTrigger moves that point - it is a fraction of the size of the panel, so a smaller value dismisses on a shorter drag - and NoSwipe turns the gesture off entirely, which is what a panel hosting something that is itself dragged needs.

OnSwipeStart, OnSwipeMove and OnSwipeEnd report the gesture as it happens, each with the distance along the axis the panel slides on.

Nested panels

A panel opened from inside another one sits at the same layer as the panel it came from, so its overlay lands underneath that panel: a click there reaches the outer panel rather than dismissing the inner one. ZIndex lifts the pair over it - the overlay takes the value given and the panel itself sits one above it - and the inner panel behaves like any other from there on.

The Escape key stops at the panel that acts on it, so the first press closes the inner panel and the outer one is only reached once the inner one is gone. The same holds for the swipe and for a click on the overlay.

Inside a container

AbsolutePosition lays the panel out against the nearest positioned ancestor instead of against the screen, so the panel and its overlay stay inside a container of the page rather than covering all of it. The container needs a position of its own for the panel to be placed against, and it clips the panel where it hides its overflow.

It leaves the page alone as well: the hold such a panel would otherwise take on the page is stood down, since taking the scrollbar off the whole page for a panel that covers one box of it moves the page around the very container being looked at. A scroller named by ScrollerSelector or ScrollerElement is still held, so a contained panel that is meant to hold the container it sits in names it there.

The panel below opens inside this box, not over the page.

Rendering and events

A panel builds its content when it opens and takes it back out once it has finished sliding away - it waits for the movement to end, so the closing is still seen with something in it. Nothing of it is rendered until the first opening, so a panel that is never opened costs nothing, and every opening starts over: a form inside one does not still hold the last thing typed into it. Type into the field below, close the panel, and open it again.

KeepMounted keeps it instead: the content goes into the page on the first opening and stays from then on, hidden while the panel is closed - which keeps it out of the tab order and out of the reach of a screen reader - so whatever state it holds survives the closing.

OnOpen is called once the panel is open and the page shows it, and OnToggle is called for both directions with the new state - which is the one callback a panel that only needs to know it changed can use. Both are called on the frame the panel changed state on; OnTransitionEnd waits until the panel has actually finished sliding, which is what measuring it or scrolling something into view inside it has to wait for.

Opened 0 times, last toggled to False, settled at False

External Icons

CloseIcon takes the glyph of the close button from an external icon library - FontAwesome, Material Icons, Bootstrap Icons - through the CSS classes that library asks for, and takes precedence over the CloseIconName that names a built-in Fluent icon.

Style & Class

Style and Class reach the root element of the panel, and Styles and Classes reach every part it is made of - the Root, the Overlay that covers the page, the Container that is the panel itself, and, on a panel that builds the chrome, the HeaderContainer, the Header, the CloseButton, the CloseIcon, the Body and the Footer. The Container is also how a panel is given a size that is not a pixel value - a percentage, a rem - which Size does not take.

The Root member is also where the panel's own custom properties are set: --bit-pnl-max is how much of the screen a panel that is not FullSize may take along the axis it slides on, and it defaults to 85%.

RTL

Dir turns the panel right-to-left, which swaps the two logical edges over: a Start panel now slides in from the right of the screen and an End one from the left, and the swipe that dismisses them follows.

API

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

BitPanel parameters

Name Type Default value Description
AbsolutePosition bool false Lays the panel out against the nearest positioned ancestor instead of against the screen, so that the panel - and the overlay that comes with it - stay inside a container of the page rather than covering all of it.
AutoToggleScroll bool false Takes the overflow off the scroller itself while the panel is open and hands it back once it closes, instead of taking the counted hold the panel otherwise takes on the page - the two would else both be holding the same page. The room the scrollbar gave back is what an AbsolutePosition panel is pushed down by.
Blocking bool false Keeps a click on the overlay from dismissing the panel, for the panels whose content has to be completed or cancelled through the panel itself. It says nothing about the Escape key or the swipe gesture.
Body RenderFragment? null Alias for ChildContent, named for the body it becomes on a panel that was given a header or a footer to lay out around it.
ChildContent RenderFragment? null The content of the panel.
Classes BitPanelClassStyles? null Custom CSS classes for different parts of the panel.
CloseButtonTitle string? null The title and accessible name of the close button, which is what a screen reader reads out for it and what the pointer shows as its tooltip. It defaults to "Close".
CloseIcon BitIconInfo? null The icon of the close button, given as the CSS classes of an external icon library. It takes precedence over CloseIconName.
CloseIconName string? null The name of the built-in Fluent UI icon of the close button. It defaults to Cancel.
Footer RenderFragment? null The footer of the panel, which stays put at the far edge of it while the content between it and the header scrolls.
FooterText string? null The text of the footer of the panel, for the footer that is nothing but a line of text. Footer takes precedence over it.
FullSize bool false Stretches the panel over the whole of the screen, which takes over from Size and from the cap that otherwise leaves a strip of the page showing beside it.
Header RenderFragment? null The header of the panel, which stays put at the edge the panel slid in from while the content below it scrolls. It is also what names the panel to a screen reader, unless TitleAriaId or AriaLabel names it instead.
HeaderText string? null The text of the header of the panel, for the header that is nothing but a title. Header takes precedence over it.
IsAlert bool false Reports the panel to assistive technologies as an alert dialog rather than a plain one, for the panels that carry an urgent message the user is expected to deal with before carrying on.
IsOpen bool false Determines the openness of the panel.
KeepMounted bool false Keeps the content of the panel in the page once it has been opened, instead of taking it back out every time the panel closes. Nothing of it is rendered until the first opening either way.
ModeFull bool false Renders the overlay in full mode that gives it an opaque background. The overlay catches the clicks meant for the page behind it either way; this is what makes it dim that page as well.
Modeless bool false Leaves the page its own clicks while the panel is open, by not rendering the overlay that otherwise covers it. A modeless panel does not report itself as a modal dialog and does not keep the keyboard inside itself.
NoAutoFocus bool false Leaves the focus where it is when the panel opens, instead of moving it into the panel. An element in the content marked with a data-autofocus attribute takes the focus instead of the first focusable one. The Escape key reaches the panel from wherever the keyboard is inside it, so a panel that never took the keyboard over is also one Escape does not reach until the user has tabbed or clicked into it.
NoDismissOnEscape bool false Keeps the Escape key from dismissing the panel, for the panels that are only meant to be closed through their own content.
NoFocusTrap bool false Lets the keyboard leave the panel while it is open, instead of cycling Tab and Shift+Tab inside it. A Modeless panel never traps the focus.
NoRestoreFocus bool false Leaves the focus wherever the panel left it when it closes, instead of handing it back to the element that had it before the panel opened. Nothing is recorded for a panel that hands nothing back.
NoScrollLock bool false Leaves the page scrolling behind the open panel, instead of holding it still. A Modeless panel never holds the page anyway, and one doing its own scroll handling through AutoToggleScroll holds its scroller itself. The gestures that land on a panel holding nothing are handed on to the scroller it names.
NoSwipe bool false Turns off the swipe gesture that otherwise dismisses the panel when it is dragged towards the edge it slid in from.
OnDismiss EventCallback<MouseEventArgs> A callback function for when the panel is dismissed. It is called for every closing of the panel: the close button, the overlay, the Escape key, a swipe, the Close and Toggle methods, and the IsOpen parameter being set to false from the outside.
OnDismissing EventCallback<BitPanelDismissArgs> A callback function invoked before the panel closes, which lets the closing be refused by setting Cancel on the arguments it is given, and tells the closings apart through their Reason. The IsOpen parameter being set to false from the outside never passes through it.
OnEscapeKeyDown EventCallback<KeyboardEventArgs> A callback function for when the Escape key is pressed inside the panel. It is called for every Escape, including the ones a panel with NoDismissOnEscape refuses to be dismissed by, which makes it the counterpart of OnOverlayClick for the keyboard.
OnOpen EventCallback A callback function for when the panel is opened.
OnOverlayClick EventCallback<MouseEventArgs> A callback function for when a click lands on the overlay of the panel. It is called before the panel is dismissed, and it is called for a Blocking panel too.
OnSwipeStart EventCallback<decimal> The event callback for when the swipe action starts on the container of the panel.
OnSwipeMove EventCallback<decimal> The event callback for when the swipe action moves on the container of the panel.
OnSwipeEnd EventCallback<decimal> The event callback for when the swipe action ends on the container of the panel.
OnToggle EventCallback<bool> A callback function for when the panel opens or closes, called with the new open state.
OnTransitionEnd EventCallback<bool> A callback function for when the panel has finished sliding in or out, called with the state it settled in. OnOpen, OnDismiss and OnToggle are called on the frame the panel changed state on, which is the start of the movement rather than the end of it.
Position BitPanelPosition? null The edge of the screen the panel slides in from. Start and End are the logical edges, so they follow the direction of the panel. It defaults to End.
Role string? null The ARIA role the panel reports itself under, which takes over from the dialog it is announced as by default. It is for the panel that is not a dialog at all: a Modeless panel left beside the page is better announced as a complementary or a region.
Size double? null The size of the panel in pixels along the axis it slides on: the width of a panel at the start or the end of the screen, and the height of one at the top or the bottom. A size that is not a pixel value is given through the Container member of Styles.
ScrollerElement ElementReference? null The element reference of the scroller whose scrolling is taken away while the panel is open, for the layouts whose scroller cannot be named by a selector. It takes precedence over ScrollerSelector, and over the scroller a BitAppShell cascades.
ScrollerSelector string? null The CSS selector of the element whose scrolling is held while the panel is open, for the layouts whose scroller is not the page itself. A panel inside a BitAppShell holds the shell's scroller without being told to; the body of the document is what is held when there is no shell and this is not set.
ShowCloseButton bool false Shows the close button of the panel, at the end of the header row. It is what a Blocking or a Modeless panel needs to be closable with the pointer at all.
Styles BitPanelClassStyles? null Custom CSS styles for different parts of the panel component.
SubtitleAriaId string? null The ARIA id of the element that describes the panel, which is what a screen reader reads out after the name of the panel when it opens.
SwipeTrigger decimal? null How far the panel has to be dragged towards the edge it slid in from before it is dismissed, as a fraction of its own size (default is 0.25). Values outside of the range greater than zero and no more than one fall back to the default.
TitleAriaId string? null The ARIA id of the element that names the panel, which is what a screen reader reads out when the panel opens. It defaults to the Header of the panel, and AriaLabel takes precedence over both.
ZIndex int? null The layer the panel and its overlay are stacked at, which takes over from the one the whole library shares. The overlay takes this value and the panel itself sits one above it, which is what a panel opened from inside another one needs.

BitPanel public members

Name Type Default value Description
Open Task Opens the panel, unless it is disabled.
Close Task Closes the panel. A panel that is already closed is left alone, and one whose OnDismissing refuses the closing stays open.
Toggle Task Opens the panel when it is closed, and closes it when it is open.

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.
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.
IsEnabled bool true Gets or sets a value indicating whether the component is enabled and can respond to user interaction.
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.

BitPanelClassStyles properties

Name Type Default value Description
Root string? null Custom CSS classes/styles for the root element of the BitPanel.
Overlay string? null Custom CSS classes/styles for the overlay of the BitPanel.
Container string? null Custom CSS classes/styles for the container of the BitPanel, which is the panel surface itself.
HeaderContainer string? null Custom CSS classes/styles for the header container of the BitPanel, which holds the header beside the close button.
Header string? null Custom CSS classes/styles for the header of the BitPanel.
CloseButton string? null Custom CSS classes/styles for the close button of the BitPanel.
CloseIcon string? null Custom CSS classes/styles for the icon of the close button of the BitPanel.
Body string? null Custom CSS classes/styles for the body of the BitPanel, which is the part that scrolls between the header and the footer.
Footer string? null Custom CSS classes/styles for the footer of the BitPanel.

BitPanelDismissArgs properties

Name Type Default value Description
Reason BitPanelDismissReason What is closing the panel: the close button, a click on the overlay, the Escape key, a swipe, or the code that opened it.
Mouse MouseEventArgs? null The click that is closing the panel, which is only there for a dismissal that came from a pointer.
Cancel bool false Set to true to refuse the dismissal and leave the panel open.

BitPanelPosition enum

Name Value Description
Start 0 The logical start edge of the screen: the left in left-to-right, the right in right-to-left.
End 1 The logical end edge of the screen: the right in left-to-right, the left in right-to-left.
Top 2 The top edge of the screen.
Bottom 3 The bottom edge of the screen.

BitPanelDismissReason enum

Name Value Description
Programmatic 0 The code that opened the panel closed it, through the Close or Toggle method.
Overlay 1 The user clicked the overlay that covers the page behind the panel.
Escape 2 The user pressed the Escape key while the keyboard was inside the panel.
Swipe 3 The user swiped the panel towards the edge it slid in from.
CloseButton 4 The user clicked the close button the panel renders in its own header.

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.