Splitter
A two-panel split with a draggable divider. The handle is a real
role="separator" with the APG window-splitter keyboard contract (arrows
step the split, Home/End jump to the limits), and dragging uses pointer
capture, so fast drags never lose the handle.
Sidebar
Content: drag the divider, or focus it and use arrow keys
import { Splitter, Box, Center, Text } from "astralis-ui";
export function SplitterDemo() {
return (
<Box w="full" h="40" border="normal" borderColor="base" rounded="lg" overflow="hidden">
<Splitter defaultSize={35} minSize={20} maxSize={80} style={{ height: "100%" }}>
<Splitter.Panel>
<Center h="full" bg="subtle">
<Text size="sm" color="muted">Sidebar</Text>
</Center>
</Splitter.Panel>
<Splitter.Handle aria-label="Resize sidebar" />
<Splitter.Panel>
<Center h="full">
<Text size="sm" color="muted">Content: drag the divider, or focus it and use arrow keys</Text>
</Center>
</Splitter.Panel>
</Splitter>
</Box>
);
}First
Second
orientation
minSize
maxSize
import { Center, Splitter, Text } from "astralis-ui";
<Splitter
style={{ height: "10rem" }}
>
<Splitter.Panel>
<Center h="full" bg="subtle">
<Text size="sm" color="muted">First</Text>
</Center>
</Splitter.Panel>
<Splitter.Handle aria-label="Resize panels" />
<Splitter.Panel>
<Center h="full">
<Text size="sm" color="muted">Second</Text>
</Center>
</Splitter.Panel>
</Splitter>
Import#
import { Splitter } from "astralis-ui";How sizing works#
The first panel's share rides a CSS variable on the root; panels are
addressed by DOM order (Panel / Handle / Panel), so there is no
registration protocol. The second panel takes the rest.
Props#
| Prop | Type | Default | Description |
|---|---|---|---|
orientation | "horizontal" | "vertical" | "horizontal" | Split axis. horizontal puts the panels side by side. |
size · defaultSize · onResize | number · number · (size: number) => void | None · 50 · None | Controlled / initial share of the first panel, in percent, and the change callback. |
minSize | number | 10 | Smallest share the first panel can shrink to, in percent. |
maxSize | number | 90 | Largest share the first panel can grow to, in percent. |
Parts#
| Prop | Type | Default | Description |
|---|---|---|---|
Splitter.Panel | div props | None | One of the two panes, addressed by DOM order. The second takes the remaining space. |
Splitter.Handle | div props | None | The draggable divider between the panels. Give it an aria-label. |
Keyboard#
The handle is a single tab stop. With it focused:
| Key | Action |
|---|---|
← / → | Shrink / grow the first panel by 2% (horizontal) |
↑ / ↓ | Shrink / grow the first panel by 2% (vertical) |
Home | Shrink the first panel to minSize |
End | Grow the first panel to maxSize |
Accessibility#
The handle renders role="separator" with aria-valuenow, aria-valuemin
and aria-valuemax, so assistive technology announces the split as a
percentage. Label it with aria-label ("Resize sidebar").