Splitter
- Layer: Component
- Base:
@ark-ui/solidSplitter - Shipped for: Document review’s two-panel layout (doc + Saltie chat)
Splits a container into resizable panels. Sizes are percentages that must sum
to 100. The resize trigger is an 8px hit area with a 1px seam that glows cyan
on hover, drag, and keyboard focus. Use onSizeChangeEnd to persist the
user’s preference.
Horizontal
Section titled “Horizontal”A — TWO PANELS, DOC + RAIL
LEFT · 60%
RIGHT · 40%
Vertical
Section titled “Vertical”B — ORIENTATION=VERTICAL
TOP
BOTTOM
Persisted
Section titled “Persisted”The handle updates in-memory state via onSizeChangeEnd. In production, write
the returned size to localStorage and rehydrate on mount.
C — PERSISTED VIA onSizeChangeEnd
65%
35%
import { Splitter } from "@risingswamp/design-system";import type { SplitterSizeChangeDetails } from "@ark-ui/solid/splitter";
<Splitter.Root size={[ { id: "doc", size: 66, minSize: 45, maxSize: 75 }, { id: "chat", size: 34, minSize: 25, maxSize: 55 }, ]} onSizeChangeEnd={(details: SplitterSizeChangeDetails) => { const doc = details.size.find((s) => s.id === "doc"); if (doc?.size != null) persist(doc.size); }}> <Splitter.Panel id="doc">{/* document body */}</Splitter.Panel> <Splitter.ResizeTrigger id="doc:chat" aria-label="Resize panels" /> <Splitter.Panel id="chat">{/* chat rail */}</Splitter.Panel></Splitter.Root>;Anatomy
Section titled “Anatomy”| Part | Role |
|---|---|
Splitter.Root | Flex container; owns orientation and panel sizes |
Splitter.Panel | A resizable region; identified by id |
Splitter.ResizeTrigger | Handle between two panels; id is "<panelA>:<panelB>" |
Splitter.Root
Section titled “Splitter.Root”| Prop | Type | Default |
|---|---|---|
orientation | "horizontal" | "vertical" | "horizontal" |
size | { id, size, minSize?, maxSize? }[] | — |
defaultSize | same shape (uncontrolled) | — |
onSizeChange | (details: SplitterSizeChangeDetails) | — |
onSizeChangeEnd | (details: SplitterSizeChangeDetails) | — |
Splitter.Panel
Section titled “Splitter.Panel”| Prop | Type | Notes |
|---|---|---|
id | string | number | Required |
snapSize | number | Snap to this size near panel edges |
Splitter.ResizeTrigger
Section titled “Splitter.ResizeTrigger”| Prop | Type | Notes |
|---|---|---|
id | `${PanelId}:${PanelId}` | Identifies which two panels it resizes |
disabled | boolean | Dim and block interaction |
step | number | Keyboard step (percent) |
aria-label | string | Defaults to “Resize panels” |
Keyboard
Section titled “Keyboard”| Key | Action |
|---|---|
ArrowLeft / ArrowRight | Resize by 1% (horizontal) |
ArrowUp / ArrowDown | Resize by 1% (vertical) |
Home | Jump to min size |
End | Jump to max size |
Enter | Toggle between last two sizes |
Token Dependencies
Section titled “Token Dependencies”| Token | Usage |
|---|---|
--colors-border | Seam colour at rest |
--colors-accent | Seam colour on hover / drag / focus |
--glow-primary | Seam glow on hover / drag |
--shadows-focus | Focus-visible ring |
--durations-fast | State transitions |
Accessibility
Section titled “Accessibility”Splitter.ResizeTriggerrenders asrole="separator"via Ark UI witharia-valuemin,aria-valuemax,aria-valuenowreflecting the resolved size.- Keyboard-reachable (Tab focusable) and announced with
aria-label. - Focus ring uses the system-wide cyan offset-glow; never a solid outline.