Import
import { ResizablePanels } from '@k8ordo/ui';Usage
value is the first pane’s share in percent; the second pane takes the rest. The root fills its parent, so give the parent a size (a vertical split needs a height). The divider takes focus; the arrow keys move it the way they point on screen, and Home / End jump to min / max. In a right-to-left page the first pane sits on the right, so ArrowLeft widens it. The panes follow the line of text, so in vertical writing mode orientation="horizontal" stacks them.
Sidebar
Content
<div className="h-48">
<ResizablePanels.Root defaultValue={30}>
<ResizablePanels.Panel>Sidebar</ResizablePanels.Panel>
<ResizablePanels.Handle />
<ResizablePanels.Panel>Content</ResizablePanels.Panel>
</ResizablePanels.Root>
</div>Vertical
orientation="vertical" stacks the two panes. The divider moves with the up and down arrow keys, and its value is the top pane’s share of the height.
Editor
Terminal
<div className="h-48">
<ResizablePanels.Root orientation="vertical">
<ResizablePanels.Panel>Editor</ResizablePanels.Panel>
<ResizablePanels.Handle />
<ResizablePanels.Panel>Terminal</ResizablePanels.Panel>
</ResizablePanels.Root>
</div>Naming the divider
The divider’s value is the first pane’s size, so name it after the first pane: point aria-labelledby at its heading. Without one it falls back to resizablePanelsHandle from the dictionary.
Files
Preview
<ResizablePanels.Root defaultValue={30}>
<ResizablePanels.Panel>
<h2 id="files-heading">Files</h2>
</ResizablePanels.Panel>
<ResizablePanels.Handle aria-labelledby="files-heading" />
<ResizablePanels.Panel>Preview</ResizablePanels.Panel>
</ResizablePanels.Root>Controlled
onChange receives the share while dragging, too. From the keyboard it moves by step.
Sidebar: 30%
Sidebar
Content
const [size, setSize] = useState(30);
<ResizablePanels.Root onChange={setSize} value={size}>
…
</ResizablePanels.Root>Props
ResizablePanels.Root
children?- Type:
ReactNode - Default: -
defaultValue?- Type:
number - Default:
50 max?- Type:
number - Default:
90 min?- Type:
number - Default:
10 onChange?- Type:
(value: number) => void - Default: -
orientation?- Type:
'horizontal'|'vertical' - Default:
'horizontal' ref?- Type:
Ref<HTMLDivElement> - Default: -
step?- Type:
number - Default:
5 value?- Type:
number - Default: -
| Prop | Type | Default |
|---|---|---|
children? | ReactNode | - |
defaultValue? | number | 50 |
max? | number | 90 |
min? | number | 10 |
onChange? | (value: number) => void | - |
orientation? | 'horizontal'|'vertical' | 'horizontal' |
ref? | Ref<HTMLDivElement> | - |
step? | number | 5 |
value? | number | - |
Type base (some attrs are managed internally): HTMLAttributes<HTMLDivElement>
ResizablePanels.Panel
children?- Type:
ReactNode - Default: -
ref?- Type:
Ref<HTMLDivElement> - Default: -
| Prop | Type | Default |
|---|---|---|
children? | ReactNode | - |
ref? | Ref<HTMLDivElement> | - |
Type base (some attrs are managed internally): HTMLAttributes<HTMLDivElement>
ResizablePanels.Handle
| Prop | Type | Default |
|---|
Type base (some attrs are managed internally): HTMLAttributes<HTMLDivElement>
Wording this component renders (labels, placeholders, and the like) comes from the message dictionary when no prop sets it. To change it, see: i18n