Components / structure
Splitter
Not a Separator. If the line cannot be dragged, it has no keyboard contract and no role beyond separator, and this component's machinery is all cost.
Summary
A draggable divider between two panes — a canvas and its inspector.
| APG pattern | Window Splitter |
| Built on | native elements |
| Status | stable |
| Since | 0.1.0 |
<Splitter id="editor" label="Resize inspector" defaultSize={70} min={30} max={85}
primary={<Canvas />} secondary={<Inspector />} />
Anatomy
Two panes with a separator between them. The separator is focusable and carries the aria-value* set.
| Part | Element | Required |
|---|---|---|
pane | <div> | yes |
separator | <div> | yes |
Properties
| Property | Values | Default | What it does |
|---|---|---|---|
orientation | horizontal · vertical | horizontal | Which way the panes are arranged, and therefore which arrow keys move the divider. |
defaultSize | number | 30 | Primary pane size as a percentage. |
min | number | 10 | The smallest the primary pane may become, as a percentage. Below this the divider clamps rather than collapsing, so a pane never disappears by accident. |
max | number | 90 | The largest the primary pane may become, as a percentage. |
step | number | 2 | Percentage points moved per arrow key press. |
label | string | required | Required — names the separator for a keyboard user. |
labelledBy | string | none | Id of the primary pane's visible heading. Wins over label. |
primary | React.ReactNode | required | The pane the size refers to and the label names. |
secondary | React.ReactNode | required | The other pane. It takes whatever is left. |
id | string | none | Optional. A stable id is generated when omitted; aria-controls is always wired. |
States
| State | Expressed as | |
|---|---|---|
| Focused | :focus-visible | |
| Hover | :hover |
Behavior
The separator takes focus and moves with arrow keys. A divider you can only drag is unusable without a pointer, which is the failure this pattern exists to prevent. Home and End collapse and expand; Enter restores the previous size from collapsed.
Accessibility
The separator is named, and the name says what moving it does — Resize inspector, not Divider.
Its hit area is widened under a coarse pointer by a pseudo-element rather than by making the line thicker, so the target grows and the appearance does not.
It has no upstream test suite. Window Splitter is one of four patterns the W3C ships no regression tests for.
Keyboard
| Key | Result |
|---|---|
Arrow keys | Move the divider by one step |
Home / End | Collapse and expand |
Enter | Restores the previous size from collapsed |
Roles, states and properties
| Attribute | Set by |
|---|---|
aria-controls | set at render |
aria-label | set at render |
aria-labelledby | set at render |
aria-orientation | set at render |
aria-valuemax | set at render |
aria-valuemin | set at render |
aria-valuenow | set at render |
role | always separator |
Focus
The separator itself takes focus, which is the failure this pattern exists to prevent — a divider you can only drag is unusable without a pointer.
Screen reader
Not recorded as verified. Stage 4 of the readiness ladder — driving each component with VoiceOver and NVDA — is unstarted across the package, and no component should claim otherwise until docs/journal/ records the session that did it.
Contrast and target size
npm run check:contrast audits every color pair this component uses across all four skins, light and dark, and fails the build on a shortfall. Two waivers are on the record in docs/audit/DEFERRED.md.
It takes the touch floor under (pointer: coarse) — the visual size is unchanged on a desktop pointer.
Tested
test/apg/partials-sweep.test.jsx
Known gaps
_No upstream requirement is recorded as not applicable._
Appearance
| Token | Used for |
|---|---|
--se-accent | background |
--se-border | background |
--se-duration-instant | transition |
--se-ease-standard | transition |
--se-focus-color | outline |
--se-focus-offset | outline-offset |
--se-focus-width | outline |
--se-space-1 | block-size, inline-size |
--se-space-2 | inset-block, inset-inline |
--se-target-min | inset-inline |
Motion
None while dragging — the pane tracks the pointer. Collapse and expand are instant, because they are a jump rather than a movement.
Content
The label names the pane that moves. If both move, name the one the reader thinks of as adjustable.
Usage
When not to use it. For a layout that could be intrinsic. data-se-layout="sidebar" gives a panel a floor and lets main take the rest with no control at all, and a splitter a reader never touches is a control that costs a tab stop for nothing.
Notes
Not a Separator. If the line cannot be dragged, it has no keyboard contract and no role beyond separator, and this component's machinery is all cost.