Resizable Panels / Splitter
Preview: Horizontal
Split view with draggable, keyboard-accessible separators (role="separator", arrow keys step 5%).
Import
import { ResizablePanels, ResizablePanel, ResizableHandle } from '@marbleui/ui'Props
<ResizablePanels>
| Prop | Type | Default | Description |
|---|---|---|---|
| children *required | ReactNode | — | |
| defaultSizes *required | number[] | — | Initial sizes in percent, one per panel (sum 100). |
| className | string | — | |
| minSize | number | 10 | |
| onSizesChange | (sizes: number[]) => void | — | |
| orientation | 'vertical' | 'horizontal' | 'horizontal' |
<ResizablePanel>
| Prop | Type | Default | Description |
|---|---|---|---|
| children *required | ReactNode | — | |
| index *required | number | — | |
| className | string | — |
<ResizableHandle>
Separator between panel `index` and `index + 1`.
| Prop | Type | Default | Description |
|---|---|---|---|
| index *required | number | — | |
| aria-label | string | — | |
| withGrip | boolean | true |
Usage notes
Split view whose panes the user can resize by dragging or with the keyboard. For a fixed layout use plain flex or grid; for showing or hiding a pane use Drawer or a collapsible Sidebar.
<ResizablePanels defaultSizes={[30, 70]} className="h-64">
<ResizablePanel index={0}>Sidebar</ResizablePanel>
<ResizableHandle index={0} aria-label="Resize sidebar" />
<ResizablePanel index={1}>Content</ResizablePanel>
</ResizablePanels>
defaultSizesare percentages, one per panel, and should sum to 100. Sizes are uncontrolled; read changes viaonSizesChange.minSizedefaults to 10.- A handle at
indexsits between panelsindexandindex + 1. Handles are focusable separators; arrow keys resize by 5% (10% with Shift). Horizontal uses Left/Right,orientation="vertical"uses Up/Down. - Give each handle a distinct
aria-label(default “Resize”) and give the container a height.
Example source · show· hide
import { ResizableHandle, ResizablePanel, ResizablePanels } from './resizable'
const Pane = ({ label }: { label: string }) => <div className="grid h-full place-items-center text-sm text-fg-muted">{label}</div>
export const styles = {
Horizontal: () => (
<ResizablePanels defaultSizes={[30, 70]} className="h-64 w-[36rem] rounded-xl border border-border bg-surface">
<ResizablePanel index={0}><Pane label="Sidebar" /></ResizablePanel>
<ResizableHandle index={0} />
<ResizablePanel index={1}><Pane label="Content" /></ResizablePanel>
</ResizablePanels>
),
'Three panes': () => (
<ResizablePanels defaultSizes={[25, 50, 25]} className="h-64 w-[36rem] rounded-xl border border-border bg-surface">
<ResizablePanel index={0}><Pane label="Files" /></ResizablePanel>
<ResizableHandle index={0} withGrip={false} />
<ResizablePanel index={1}><Pane label="Editor" /></ResizablePanel>
<ResizableHandle index={1} withGrip={false} />
<ResizablePanel index={2}><Pane label="Preview" /></ResizablePanel>
</ResizablePanels>
),
Vertical: () => (
<ResizablePanels orientation="vertical" defaultSizes={[60, 40]} className="h-72 w-96 rounded-xl border border-border bg-surface">
<ResizablePanel index={0}><Pane label="Editor" /></ResizablePanel>
<ResizableHandle index={0} />
<ResizablePanel index={1}><Pane label="Terminal" /></ResizablePanel>
</ResizablePanels>
),
}Source: packages/ui/src/resizable/resizable.tsx
Catalog
- Category
- layout
- Priority
- Core
- Primitive
- custom