Surfaces
Splitter
The BitSplitter divides a container into two panels, side by side or stacked, with a gutter between them that the reader drags to give one panel more room and the other less. Each panel can declare a starting size and the minimum and maximum it is allowed to reach, the split is held as a percentage that survives the container being resized and can be bound, and the first panel can be folded away and brought back - by a control on the gutter, by the keyboard, by a drag that snaps it shut, or from code. A splitter can remember where it was left, report every stage of a resize, be held to a grid of its own, and move a line instead of the panels where the content is too heavy to lay out on every frame. The gutter is a WAI-ARIA window splitter: it takes the focus, moves with the arrow keys, and reports where it stands to a screen reader.
Usage
Every example is live. Open its code to see exactly what produced the component running underneath.
Basic
FirstPanel and SecondPanel is laid out on either side of the gutter, which
starts halfway across the splitter. Drag the gutter to move the split, give it the focus and move it with the
arrow keys (the whole keyboard is below), or double-click it to put the panels
back where the parameters had them. A panel scrolls its own content, so neither side can push the other out of the
splitter. A splitter fills whatever box it is given, so the height comes from the page around it - here, from the
Style on the splitter itself.
Once upon a time, stories wove connections between people, a symphony of voices crafting shared dreams.
Each word carried meaning, each pause brought understanding. The spaces here are open for growth.
Vertical
Vertical stacks the two panels instead of placing them side by side, and the gutter becomes a
horizontal bar that moves with the up and down arrow keys. Everything else reads the same way round: the panel
sizes and their minimums and maximums become heights, and the first panel is the one on top.
Once upon a time, stories wove connections between people, a symphony of voices crafting shared dreams.
Each word carried meaning, each pause brought understanding. The spaces here are open for growth.
Panel size
FirstPanelSize and SecondPanelSize pin a panel to a size in pixels and let the other one
take whatever is left, which is the layout of a sidebar beside a document. They are the size the splitter starts
at: from the first drag on the split is held as a percentage, and a double-click on the gutter hands the layout
back to them.
Min & max size
MinSize and MaxSize parameters, in pixels, are the range the gutter is held to -
by the pointer, by the keyboard and by Percent alike. What one panel asks for bounds the other from
the far side, so a minimum on the second panel is what keeps the first one from being dragged over it. The range
is measured off the panels rather than read back from these parameters, so a minimum or maximum a stylesheet puts
on a panel through Classes - as a percentage, or in any other unit - holds the gutter just as firmly.
Percent
Percent is the whole layout in one number: the share of the splitter the first panel takes up. Being a
share rather than a length, it keeps its proportions while the container is resized, and being bindable it works
both ways - every drag, key press and collapse reports back through @bind-Percent, and writing to it
moves the gutter. It takes precedence over the two panel sizes while it has a value.
Drag step
DragStep is a grid, in pixels, that the split comes to rest on: the gutter follows the pointer but
lands on the nearest multiple of it rather than wherever the pointer happens to be, which is what lines a panel
up with a column of a grid, a tile or a row of text. The keyboard is held to the same multiples, so both ways of
moving the gutter agree on where it is allowed to stop.
Lazy resize
LazyResize is the way to drag one of those: a line moves instead of the panels, and they are laid out
once, where the line was left. Everything else is unchanged - the keyboard, the minimum and maximum sizes, the
snap to collapse and the events all behave as they do on any other splitter.
Keyboard
KeyboardStep pixels - ten by default - and hold it inside
the minimum and maximum sizes of both panels; Page Up, Page Down and an arrow key
held with Shift move it ten steps at once; Home and End take it to the
smallest and the largest size the panels allow; Escape abandons a drag that is under way, putting
the panels back exactly as it found them. On a collapsible splitter Enter folds the first panel
away and brings it back, and so does Ctrl with the arrow key that points at it or away from it.
A double-click hands the layout back to the panel size parameters unless NoResetOnDoubleClick
takes that away.
Collapsible
Collapsible lets the first panel be folded away: press Enter or Ctrl with an
arrow key on the gutter, drag it close enough to the start of the splitter for it to snap shut, or press the gutter
of an already folded panel to open it again - and a control on the gutter can
offer the same to the pointer. CollapsedSize is the sliver it is left at: a folded panel keeps its
content in the DOM and drops the minimum size it holds while it is open, so it can close past a minimum that would
otherwise stop it. Collapsed is bindable, so the page always knows, and expanding puts the panel back
at the size it had before it was folded rather than at some default.
SnapSize names that distance instead:
here the panel only shuts inside the first 40 pixels, so the whole of the range above it stays draggable.
CollapseSecondPanel moves all of that to the other side of the gutter, which is what an inspector, a
properties pane or a preview at the far end of the splitter needs. Nothing else changes its meaning:
Collapsed, CollapsedSize, SnapSize, the keys and the methods all go on
describing the one panel that folds, and Percent still describes the first panel - so the split the
second panel comes back to is the one it left.
Collapse button
ShowCollapseButton draws the fold on the gutter itself. Without it the only ways in are a key press
and a drag that happens to reach the edge, neither of which a reader can see is on offer; with it the gutter says
so. The chevron points at what the next press will do and turns with the orientation of the splitter and the
writing direction of the page, and CollapseIconName and ExpandIconName - or
CollapseIcon and ExpandIcon, for an external icon set - put something else there. It is
the pointer's way to what the gutter already answers to from the keyboard, so it stays out of the tab order and
out of the accessibility tree: a screen reader is handed the separator and the fold it offers once, not twice.
Cancelling a collapse
OnCollapsing is asked before the panel moves, with what is about to happen and what asked for it -
the gutter, a drag that snapped it shut, one of the methods, or the remembered position being restored. Setting
Cancel on the arguments leaves the panel exactly as it is, which is how a fold is made to wait for
a confirmation or a save. The callback is awaited, and nothing else folds the panel while it is running.
Programmatic control
SetPercent puts the gutter at a share
of the splitter (clamped to 0-100, and still held to the minimum and maximum sizes of both panels),
GetPercent reads the share the first panel takes up at this moment - measured off the panels, so it
answers even for a split nobody has moved yet, which Percent does not hold until the first drag -
ResetSize hands the layout back to the panel size parameters, Collapse,
Expand and ToggleCollapse fold the collapsible panel away and back - none of them turned
away by Collapsible, which is about what the reader may do to the gutter - and
FocusAsync puts the keyboard on the gutter. A splitter whose Percent or
Collapsed the page holds one way keeps what the page gave it: the state is the page's, and these
methods do not take it back.
Events
OnResizeStart opens a resize and exactly one of OnResizeEnd and
OnResizeCancel closes it - the second of those when Escape, or the browser taking the
pointer away, puts the panels back where the resize found them - so whatever a page sets aside for the duration
of one always has somewhere to pick it up again. OnResize reports the resize as it happens, one call
per frame of a drag and one per key press; each of the four carries the share of the splitter the first panel
takes up. OnCollapsedChange reports the panel being folded away and brought back, and
OnGutterDoubleClick the gutter being double-clicked, whether or not that also resets the splitter.
A splitter with no handler for OnResize makes no call at all while it is being dragged, so leave it
unset where only the final position matters.
Persistence
PersistKey has the splitter remember where the gutter was left - and whether the first panel was
folded away - so the reader finds the layout they arranged the last time they were here. It is kept in the
browser's local storage under that key, or in the session storage instead with
PersistInSessionStorage, and the key has to be unique to the splitter within the origin: two
splitters sharing one key share one position. What comes back is offered the way a drag is, so a page holding
Percent or Collapsed one way keeps what it declared. Move the gutter below and reload
the page.
Read-only & disabled
ReadOnly is a split that is not up for negotiation: the splitter looks exactly as it does anywhere
else, but the gutter cannot be dragged or moved from the keyboard. IsEnabled="false" takes the resize
away too and dims the whole component with it. Both leave the gutter out of the tab order and hand it back to a
screen reader as the plain rule it then is rather than as a control with a position; the public methods still
work in either case.
Nested
Gutter size
GutterSize is the thickness of the gutter in pixels. However thin it is drawn, the strip that answers a
press is widened evenly on both sides up to GutterHitSize - 24 pixels by default, and 44 wherever the
pointer is a coarse one - so a hairline gutter is still something a finger can find, and none of that reaches into
the layout: the panels give up no room for it. A gutter already thicker than the floor is left exactly as it is.
Gutter icon
GutterIconName puts a built-in Fluent UI icon in the gutter in place of the default grip, which gives
the reader something to aim at on a wider gutter.
Gutter template
GutterTemplate replaces what is drawn inside the gutter altogether. The gutter itself is the
separator - the thing the pointer drags and the keyboard moves - so what goes in here is decoration: a control of
its own in there would be a second tab stop on something a screen reader reports as a single separator.
External Icons
Style & Class
Style and Class dress the root element - which is where the height of a splitter is set,
since it fills whatever box it is put in - while Styles and Classes reach the parts
inside it: the two panels, the gutter, the icon or grip drawn in the gutter, the collapse control and its icon,
and the line a lazy drag moves. A minimum or maximum a class puts on a panel holds the gutter just as firmly as
the parameters do, and in any unit, because the range is measured off the panels rather than read back from C#.
RTL
API
Every parameter, public member, sub-class and enum this component exposes.
BitSplitter parameters
| Name | Type | Default value | Description |
|---|---|---|---|
| Classes | BitSplitterClassStyles? | null | Custom CSS classes for different parts of the BitSplitter. |
| CollapseIcon | BitIconInfo? | null | The icon of the collapse button while the panel that folds is open, using BitIconInfo for external icon library support. Takes precedence over CollapseIconName when both are set. |
| CollapseIconName | string? | null | The name of the built-in Fluent UI icon shown on the collapse button while the panel that folds is open. The default is a chevron pointing at the panel that is about to be folded away, which follows the orientation of the splitter, which panel folds and the writing direction of the page. |
| Collapsed | bool | false | Whether the panel that folds - the first one, or the second where CollapseSecondPanel says so - is currently collapsed. It can be bound, so a collapse the user carries out on the gutter is reported back to the page. A collapsed panel keeps its content in the DOM and is folded down to CollapsedSize, ignoring the minimum size it would otherwise hold, while the panel left standing takes the whole splitter. |
| CollapsedSize | int | 0 | The size, in pixels, the folded panel is held at while it is collapsed. |
| Collapsible | bool | false | Lets a panel be collapsed - the first one, or the second where CollapseSecondPanel says so: pressing Enter on the gutter folds it away and opens it again, so does Ctrl with an arrow key and the control ShowCollapseButton draws, dragging the gutter close enough to that panel's own edge of the splitter snaps it shut, and Collapse/Expand/ToggleCollapse do the same from code. |
| CollapseSecondPanel | bool | false | Folds the second panel away rather than the first one, which is what an inspector, a properties pane or a preview sitting at the far end of the splitter needs. It moves what Collapsible offers to the other side of the gutter and nothing else: Collapsed, CollapsedSize, SnapSize, the keys, the collapse control and the Collapse/Expand/ToggleCollapse methods all go on meaning the one panel that folds, and Percent still describes the first panel. |
| DragStep | int | 0 | The grid, in pixels, a drag of the gutter moves the split along: the first panel comes to rest on a multiple of this rather than wherever the pointer happens to be. The keyboard is held to the same multiples. The default of 0 is no grid at all. |
| ExpandIcon | BitIconInfo? | null | The icon of the collapse button while the panel that folds is away, using BitIconInfo for external icon library support. Takes precedence over ExpandIconName when both are set. |
| ExpandIconName | string? | null | The name of the built-in Fluent UI icon shown on the collapse button while the panel that folds is away. The default is a chevron pointing at the room the panel is about to come back into. |
| FirstPanel | RenderFragment? | null | The content for the first panel. |
| FirstPanelSize | int? | null | The initial size of the first panel in pixels. From the first drag on, the split is held as a percentage in Percent, which takes precedence over this and over SecondPanelSize. |
| FirstPanelMaxSize | int? | null | The max size of first panel in pixels. |
| FirstPanelMinSize | int? | null | The min size of first panel in pixels. |
| GutterHitSize | int? | null | The smallest strip, in pixels, a pointer has to land in to take hold of the gutter. A gutter drawn narrower than this still answers a press that lands within the strip, which reaches past what is drawn evenly on both sides without taking any room from the panels. The default is 24, the target size WCAG asks for, and 44 wherever the pointer is a coarse one. |
| GutterIcon | BitIconInfo? | null | The icon for the BitSplitter gutter using BitIconInfo for external icon library support. Takes precedence over GutterIconName when both are set. |
| GutterIconName | string? | null | The name of the built-in Fluent UI icon to render in the BitSplitter gutter. Ignored when GutterIcon is also set. |
| GutterSize | int? | null | The size of BitSplitter gutter in pixels. |
| GutterTemplate | RenderFragment? | null | The custom content of the gutter, in place of the icon or of the default grip indicator. The gutter is the separator itself, so what goes in here is decoration rather than a control. |
| KeyboardStep | int | 10 | How far, in pixels, one press of an arrow key on the gutter moves the split. Page Up and Page Down, and an arrow key held with Shift, move it ten of these steps at a time; Home and End take it all the way to the smallest and the largest size the panels allow. |
| LazyResize | bool | false | Moves a line rather than the panels while the gutter is being dragged, and puts the panels where it was left only once the drag is over. It is what makes a panel holding a table of thousands of rows, an editor or a chart draggable: the cost of the drag becomes a single layout at its end. |
| NoResetOnDoubleClick | bool | false | Keeps the gutter from resetting the splitter to the sizes its parameters declare when it is double-clicked. |
| OnCollapsedChange | EventCallback<bool> | The callback invoked when the panel that folds is collapsed or expanded. | |
| OnCollapsing | EventCallback<BitSplitterCollapseArgs> | The callback invoked before the panel that folds is collapsed or expanded, with what is about to happen and what asked for it. Set Cancel on the arguments to leave the panel as it is. The callback is awaited, and nothing else folds the panel while it is running. | |
| OnGutterDoubleClick | EventCallback | The callback invoked when the gutter is double-clicked, whether or not the double-click also resets the splitter. | |
| OnResize | EventCallback<double> | The callback invoked continuously while the gutter is being dragged, with the new share of the splitter the first panel takes up, as a percentage. It is coalesced to one call per animation frame, and a splitter with no handler for it makes no interop call at all while it is being dragged. | |
| OnResizeCancel | EventCallback<double> | The callback invoked when a resize is abandoned rather than finished - by Escape, or by the browser taking the pointer away - with the share of the splitter the first panel is put back to. Exactly one of this and OnResizeEnd follows every OnResizeStart. | |
| OnResizeEnd | EventCallback<double> | The callback invoked when a resize has finished, with the share of the splitter the first panel ended up taking, as a percentage. | |
| OnResizeStart | EventCallback<double> | The callback invoked when a resize starts, with the share of the splitter the first panel takes up at that moment, as a percentage. | |
| PersistKey | string? | null | The key the splitter remembers its position under, so that a reader who has moved the gutter finds it where they left it the next time the page is opened. Both the position and whether the first panel was folded away are kept, and what is restored is offered to the component the way a drag is. The key has to be unique to the splitter within the origin. |
| PersistInSessionStorage | bool | false | Keeps what PersistKey remembers in the browser's session storage rather than its local storage, so the position lasts as long as the tab and no longer. |
| Percent | double? | null | The share of the splitter the first panel takes up, as a percentage between 0 and 100. It survives the container being resized and can be bound, so every drag, key press and collapse is reported back to the page. While it has a value it takes precedence over FirstPanelSize and SecondPanelSize. |
| ReadOnly | bool | false | Keeps the splitter as it is: the gutter is still shown and still looks like itself, but it cannot be dragged or moved from the keyboard. |
| SecondPanel | RenderFragment? | null | The content for the second panel. |
| SecondPanelSize | int? | null | The initial size of the second panel in pixels. Ignored while Percent has a value, which is the case from the first drag on. |
| SecondPanelMaxSize | int? | null | The max size of second panel in pixels. |
| SecondPanelMinSize | int? | null | The min size of second panel in pixels. |
| ShowCollapseButton | bool | false | Draws a control on the gutter that folds the collapsible panel away and brings it back, so that a reader working with the pointer can see that the panel folds at all. Only a Collapsible splitter has one. It is the pointer's way to what the gutter already does from the keyboard, so it stays out of the tab order and out of the accessibility tree. |
| SnapSize | int | 0 | How small, in pixels, a drag has to leave the panel that folds for it to snap shut instead of staying open. Only a Collapsible splitter snaps at all. The default of 0 leaves the splitter to work it out from the minimum size of the panel: half of it, or a twentieth of the splitter where there is no minimum. |
| Styles | BitSplitterClassStyles? | null | Custom CSS styles for different parts of the BitSplitter. |
| Vertical | bool | false | Sets the orientation of BitSplitter to vertical, stacking the two panels instead of placing them side by side. |
BitSplitter public members
| Name | Type | Default value | Description |
|---|---|---|---|
| Collapse | Task | Collapses the panel that folds. Does nothing if it is already collapsed. Not turned away by Collapsible, which is about what the reader may do to the gutter. | |
| Expand | Task | Expands the panel that folds, putting the split back where it was before the fold. | |
| ToggleCollapse | Task | Collapses the panel that folds if it is expanded and expands it if it is collapsed. | |
| SetPercent | Task | Moves the split so that the first panel takes up the given share of the splitter, as a percentage between 0 and 100. The value is still held to the minimum and maximum sizes of both panels. | |
| GetPercent | ValueTask<double?> | Reads the share of the splitter the first panel takes up at this moment, as a percentage, measured off the panels themselves rather than read back from Percent. It is the only way to a split nobody has moved yet, which Percent does not hold until the first drag. A splitter whose JavaScript side is not up, and one laid out in a box with no room in it, answer null. | |
| ResetSize | Task | Clears Percent and hands the layout back to FirstPanelSize and SecondPanelSize - which is what a double-click on the gutter does. | |
| FocusAsync | ValueTask | Gives the focus to the gutter, which is the control a splitter is driven by. The overload taking a bool prevents the gutter from being scrolled into view. |
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. |
BitSplitterCollapseArgs properties
| Name | Type | Default value | Description |
|---|---|---|---|
| IsCollapsing | bool | The state the panel that folds is about to move to: true while it is being folded away, false while it is being brought back. | |
| Reason | BitSplitterCollapseReason | What made the panel collapse or expand: the gutter, a drag that snapped it shut, a call to one of the Collapse, Expand and ToggleCollapse methods, or the remembered position being restored. | |
| Cancel | bool | false | Set to true to cancel the collapse or the expansion and leave the panel as it is. |
BitSplitterClassStyles properties
| Name | Type | Default value | Description |
|---|---|---|---|
| Root | string? | null | The custom CSS class/style for the root element of the BitSplitter. |
| CollapseButton | string? | null | The custom CSS class/style for the control on the gutter that folds the first panel of the BitSplitter away and brings it back. |
| CollapseButtonIcon | string? | null | The custom CSS class/style for the icon of the control on the gutter that folds the first panel of the BitSplitter away and brings it back. |
| FirstPanel | string? | null | The custom CSS class/style for the first panel of the BitSplitter. |
| Gutter | string? | null | The custom CSS class/style for the gutter (the separator) of the BitSplitter. |
| GutterIcon | string? | null | The custom CSS class/style for the icon rendered inside the gutter of the BitSplitter. |
| GutterIndicator | string? | null | The custom CSS class/style for the default grip indicator rendered inside the gutter of the BitSplitter. |
| Preview | string? | null | The custom CSS class/style for the line a lazy drag moves in place of the panels of the BitSplitter. |
| SecondPanel | string? | null | The custom CSS class/style for the second panel of the BitSplitter. |
BitIconInfo properties
| Name | Type | Default value | Description |
|---|---|---|---|
| Name | string? | null | Gets or sets the name of the icon. |
| BaseClass | string? | null | Gets or sets the base CSS class for the icon. For built-in Fluent UI icons, this defaults to "bit-icon". For external icon libraries like FontAwesome, you might set this to "fa" or leave empty. |
| Prefix | string? | null | Gets or sets the CSS class prefix used before the icon name. For built-in Fluent UI icons, this defaults to "bit-icon--". For external icon libraries, you might set this to "fa-" or leave empty. |
BitSplitterCollapseReason enum
| Name | Value | Description |
|---|---|---|
| Gutter | 0 | The gutter was pressed, or moved by the Enter key or Ctrl with an arrow key. |
| Drag | 1 | The gutter was dragged close enough to the panel's own edge of the splitter for it to snap shut. |
| Method | 2 | The Collapse, Expand or ToggleCollapse method of the splitter was called. |
| Restore | 3 | The position the splitter had remembered under its PersistKey was restored. |
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.