The line between two panes that the reader drags, or moves with the arrow keys, to give one pane more room and the other less.
Options
| Choice | Values | Default | What it does |
|---|---|---|---|
orientationsmbk-splitter--orientation-<value> | verticalhorizontal | vertical | Vertical is a line between two columns side by side, moved left and right. Horizontal is a line between two stacked panes, moved up and down. |
Examples
Usage
A message list beside the open message. Drag the line, or focus it and press Left or Right; Home and End give the list its smallest and largest width.
Stacked panes
A horizontal line between an editor and its output, moved with Up and Down.
Sizing the pane after the line
The value measures the settings panel after the line, so dragging the line left makes the settings wider.
Without the grip
The two halves of the line meet; the hit area is as wide as with the grip.
While dragged
The line turns brand and twice as thick, and the dots turn brand, so the change is not shown by color alone.
Disabled
The line in the disabled color and the dots without their pill. It cannot be focused or moved.
Guidelines
Purpose
The line between two panes that the reader moves to give one pane more room and the other less: a list and the item it opens, a preview and its settings, an editor and its output. The reader drags it, or focuses it and uses the arrow keys. It differs from the divider, which only separates two things and cannot be moved or focused.
When to use
- Two panes whose best share of the space depends on the reader and the task, such as a wide preview with narrow settings, or the reverse.
- A pane the reader often wants larger for a moment: a file list, a log, an inspector.
When not to use
- Two parts of a page that always keep the same share. Use a fixed layout, with a divider between them if they need a line.
- A choice between a few set sizes, such as compact and wide. Use a segmented control or a button that toggles the pane.
- A phone, or any narrow space. The panes stack there, and the splitter is not shown.
Usage rules
Do
- Give each pane a smallest size at which its content still works, and a largest that leaves the other pane usable.
- Name the splitter for the pane it sizes.
- Store the size where the reader expects it kept, and pass it back the next time.
Don't
- Use a divider where the reader should be able to move the line; it cannot be focused or dragged.
- Hide the grip on a splitter that is hard to notice, such as one between two panes of the same color.
- Leave a splitter in a narrow layout; stack the panes instead.
Name the splitter for the pane it sizes, and keep the grip where the two panes share a color.
A divider between two panes cannot be focused or dragged, so the reader cannot give either one more room.
Anatomy
- The block: the hit area, 24 across and as long as the panes, a separator the reader can focus. Vertical is a line between two columns side by side; horizontal is a line between two stacked panes.
line: the line, in two halves, one either side of the grip. Without the grip the two halves meet.grip: an optional raised pill in the middle of the line, holdingicon, six dots. On unless turned off.
Behavior
The page owns the panes. The splitter keeps a value, the size in pixels of the pane it measures, and reports every change; the page sizes the pane from it, and the other pane takes the rest. By default the value measures the pane before the line (the left one in a left-to-right page, the upper one of two stacked panes); it can measure the pane after it instead. The splitter stops at the pane's smallest and largest sizes, whichever way it is moved. It does not remember its value: a page that wants the size kept stores it and passes it back.
Dragging with a mouse, a pen or a finger moves the line with the pointer. While it is dragged the line turns brand and twice as thick, and the grip's dots turn brand. Under the pointer the hit area takes a light fill and the line darkens. On a touch screen the hit area reaches 44 across without widening the gap between the panes.
Where the layout is narrow the splitter is not shown, which also takes it out of the Tab order; the page stacks its two panes there itself, under the same layout switch. A disabled splitter keeps its line, in the disabled color, with the grip's dots and no pill, and cannot be focused or moved.
Accessibility
What it does for you
- It is a separator the reader can focus, with its orientation, its value, its smallest and largest values, and the value in words. A screen reader hears "separator", its name and how far the pane is between its smallest and largest size, as a percentage, unless the page gives other words.
- A vertical line moves with Left and Right, which follow the line on the screen in a right-to-left page too; a horizontal line moves with Up and Down. Each press moves it 16 pixels unless the page sets another step. Home gives the pane its smallest size, End its largest.
- Dragging is not the only way to move it: the keys do it too.
- The focus ring is drawn around the whole hit area.
- The hit area is at least 24 across, so a pointer does not need precision to grab it.
What you must do
- Name it for the pane it sizes, such as "Resize settings panel", and point
aria-controlsat that pane's id. - A reader who uses a pointer and cannot drag needs another way, so a page where the size matters offers set sizes beside the panes, such as a button that widens a pane.
- In hand-written markup, give it the separator role, a Tab stop,
aria-orientation,aria-valuenow,aria-valuemin,aria-valuemaxand a name, and move it with script; without script it is a line that does not move.
How to test
- Tab to it: the focus ring shows around the whole hit area, in both themes and in a forced-color mode.
- Press the arrow keys that follow the line, then Home and End: the pane grows, shrinks and stops at its smallest and largest sizes.
- With a screen reader, it is read as a separator by its name, with its value as a percentage.
- On a touch screen, the line is grabbed by a hit area 44 across.
- Check that the page offers set sizes, such as a button that widens a pane, for a reader who cannot drag.
Keyboard
| Key | What it does |
|---|---|
| Tab | Moves focus to the splitter. It is not in the Tab order where the layout is narrow and the splitter is hidden, or when it is disabled. |
| Left ArroworRight Arrow | On a vertical line, moves it by one step, following the line on the screen in a right-to-left page too. |
| Up ArroworDown Arrow | On a horizontal line, moves it by one step. |
| Home | Gives the pane its smallest size. |
| End | Gives the pane its largest size. |
Source
The files the splitter is made of. Its folder on GitHub (opens in a new tab) holds them with its wrapper and its document.
Stylesheet
/* smbk-splitter — Splitter. Figma "Splitter" 7117:70.
* A handle between two panes: a hit area 24 across and as long as the panes, holding a line in two halves and,
* between them, an optional grip, a raised pill with six dots. Dragging it, or the arrow keys, give one pane more
* room; the wrapper keeps the value and the page sizes its panes from it. Under the pointer the hit area takes the
* ghost fill and the line the strong border; while it is dragged the line turns brand and twice as thick, so the
* change is not shown by color alone. Focus draws the system's ring around the hit area. Where the layout is narrow
* the page stacks its panes and the splitter is not shown, which also takes it out of the Tab order. */
.smbk-splitter {
box-sizing: border-box;
position: relative;
display: flex;
flex: none;
flex-direction: column;
align-items: center;
align-self: stretch;
width: var(--smbk-size-control-xs);
border-radius: var(--smbk-radius-control-xs);
cursor: col-resize;
touch-action: none;
user-select: none;
-webkit-user-select: none;
}
.smbk-splitter--orientation-horizontal {
flex-direction: row;
width: auto;
height: var(--smbk-size-control-xs);
cursor: row-resize;
}
/* The line: two halves, one either side of the grip, meeting where there is none. */
.smbk-splitter__line {
flex: 1 1 0;
width: var(--smbk-border-width-hairline);
background: var(--smbk-color-border-groove-top);
}
.smbk-splitter--orientation-horizontal .smbk-splitter__line {
width: auto;
height: var(--smbk-border-width-hairline);
}
.smbk-splitter__grip {
display: flex;
flex: none;
align-items: center;
justify-content: center;
width: var(--smbk-size-16);
height: var(--smbk-size-24);
border-radius: var(--smbk-radius-full);
background: var(--smbk-color-surface-raised);
box-shadow: var(--smbk-elevation-control);
}
.smbk-splitter--orientation-horizontal .smbk-splitter__grip {
width: var(--smbk-size-24);
height: var(--smbk-size-16);
}
.smbk-splitter__icon {
font-size: var(--smbk-size-icon-sm);
color: var(--smbk-color-icon-subtle);
}
/* ---- states: hover, focus, dragging, disabled ---- */
@media (hover: hover) {
.smbk-splitter:not([aria-disabled='true']):hover {
background: var(--smbk-color-action-ghost-background-hover);
}
.smbk-splitter:not([aria-disabled='true']):hover .smbk-splitter__line {
background: var(--smbk-color-border-strong);
}
}
.smbk-splitter:focus-visible {
outline: var(--smbk-focus-ring-width) solid var(--smbk-color-border-focus);
outline-offset: var(--smbk-focus-ring-offset);
}
.smbk-splitter[data-dragging]:not([aria-disabled='true']) {
background: transparent;
}
.smbk-splitter[data-dragging]:not([aria-disabled='true']) .smbk-splitter__line {
width: var(--smbk-border-width-emphasis);
background: var(--smbk-color-border-brand);
}
.smbk-splitter--orientation-horizontal[data-dragging]:not([aria-disabled='true']) .smbk-splitter__line {
width: auto;
height: var(--smbk-border-width-emphasis);
}
.smbk-splitter[data-dragging]:not([aria-disabled='true']) .smbk-splitter__icon {
color: var(--smbk-color-icon-brand);
}
.smbk-splitter[aria-disabled='true'] {
cursor: default;
}
.smbk-splitter[aria-disabled='true'] .smbk-splitter__line {
background: var(--smbk-color-border-control-disabled);
}
.smbk-splitter[aria-disabled='true'] .smbk-splitter__grip {
background: transparent;
box-shadow: none;
}
.smbk-splitter[aria-disabled='true'] .smbk-splitter__icon {
color: var(--smbk-color-icon-disabled);
}
/* ---- touch: the hit area reaches the comfortable target without widening the gap between the panes ---- */
@media (pointer: coarse) {
.smbk-splitter::before {
content: '';
position: absolute;
inset-block: 0;
inset-inline: calc((var(--smbk-size-control-xs) - var(--smbk-size-target-comfortable)) / 2);
}
.smbk-splitter--orientation-horizontal::before {
inset-block: calc((var(--smbk-size-control-xs) - var(--smbk-size-target-comfortable)) / 2);
inset-inline: 0;
}
}
/* ---- narrow: the page stacks its panes, and the splitter is not shown ---- */
@container style(--smbk-layout: narrow) {
.smbk-splitter {
display: none;
}
}
/* ---- forced colors: the line and the grip's edge in the text color ---- */
@media (forced-colors: active) {
.smbk-splitter__line {
forced-color-adjust: none;
background: CanvasText;
}
.smbk-splitter__grip {
border: var(--smbk-border-width-hairline) solid CanvasText;
}
.smbk-splitter[aria-disabled='true'] .smbk-splitter__line {
background: GrayText;
}
.smbk-splitter:focus-visible {
outline-color: CanvasText;
}
}Tokens it reads
| Token and CSS | Value | Preview | Foundation |
|---|---|---|---|
| size.control.xs--smbk-size-control-xs | 24px | Size | |
| radius.control.xs--smbk-radius-control-xs | 2px | Radius | |
| border-width.hairline--smbk-border-width-hairline | 1px | Border width | |
| color.border.groove-top--smbk-color-border-groove-top | light: #c4cdd8dark: #00000066changes with theme | Color | |
| size.16--smbk-size-16 | 16px | Size | |
| size.24--smbk-size-24 | 24px | Size | |
| radius.full--smbk-radius-full | 9999px | Radius | |
| color.surface.raised--smbk-color-surface-raised | light: #f9fafbdark: #232527changes with theme | Color | |
| elevation.control--smbk-elevation-control | light: 0px 0px 1px 0px #373d430d, 0px 1px 2px 0px #373d431a, 0px 2px 4px 0px #373d430ddark: 0px 0px 1px 0px #0000001a, 0px 1px 2px 0px #00000026, 0px 2px 4px 0px #0000001a | Elevation | |
| size.icon.sm--smbk-size-icon-sm | 16px | Size | |
| color.icon.subtle--smbk-color-icon-subtle | light: #4e555edark: #c4cdd8changes with theme | Color | |
| color.action.ghost.background-hover--smbk-color-action-ghost-background-hover | light: #373d4326dark: #606a754dchanges with theme | Color | |
| color.border.strong--smbk-color-border-strong | light: #9ba5b1dark: #373d43changes with theme | Color | |
| focus.ring.width--smbk-focus-ring-width | 2px | Focus | |
| color.border.focus--smbk-color-border-focus | light: #cc0d0ddark: #f34336changes with theme | Color | |
| focus.ring.offset--smbk-focus-ring-offset | 2px | Focus | |
| border-width.emphasis--smbk-border-width-emphasis | 2px | Border width | |
| color.border.brand--smbk-color-border-brand | #cc0d0d | Color | |
| color.icon.brand--smbk-color-icon-brand | light: #cc0d0ddark: #fe7d6dchanges with theme | Color | |
| color.border.control-disabled--smbk-color-border-control-disabled | light: #c4cdd8dark: #606a75changes with theme | Color | |
| color.icon.disabled--smbk-color-icon-disabled | light: #9ba5b1dark: #606a75changes with theme | Color | |
| size.target.comfortable--smbk-size-target-comfortable | 44px | Size |
Manifest
{
"name": "splitter",
"block": "smbk-splitter",
"summary": "The line between two panes that the reader drags, or moves with the arrow keys, to give one pane more room and the other less.",
"adapt": "css",
"axes": {
"orientation": {
"values": [
"vertical",
"horizontal"
],
"default": "vertical",
"description": "Vertical is a line between two columns side by side, moved left and right. Horizontal is a line between two stacked panes, moved up and down."
}
},
"flags": {},
"parts": [
"line",
"grip",
"icon"
],
"figmaNodeId": "7117:70"
}