Splitter
Features
- Supports keyboard interaction.
- Supports horizontal/vertical layout.
- Supports nested layout.
- Supports Right to Left direction.
- Can resize across another panel.
- Can be mounted conditionally.
Installation
Install the component from your command line.
$ npm add reka-uiAnatomy
Import all parts and piece them together.
<script setup>
import { SplitterGroup, SplitterPanel, SplitterResizeHandle } from 'reka-ui'
</script>
<template>
<SplitterGroup>
<SplitterPanel />
<SplitterResizeHandle />
</SplitterGroup>
</template>API Reference
Group
Contains all the parts of a Splitter.
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwrite by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
autoSaveId | null | string | nullUnique id used to auto-save group arrangement via |
direction* | 'vertical' | 'horizontal'The group orientation of splitter. | |
id | string | nullGroup id; falls back to | |
keyboardResizeBy | 10 | number | nullStep size when arrow key was pressed. |
storage | defaultStorage | PanelGroupStorageCustom storage API; defaults to localStorage |
| Emit | Payload |
|---|---|
layout | [val: number[]]Event handler called when group layout changes |
| Slots (default) | Payload |
|---|---|
layout | number[]Current size of layout |
| Data Attribute | Value |
|---|---|
[data-orientation] | "vertical" | "horizontal" |
[data-state] | "collapsed" | "expanded" | "Present when collapsbile" |
Panel
A collapsible section.
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwrite by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
collapsedSize | numberThe size of panel when it is collapsed. | |
collapsible | booleanShould panel collapse when resized beyond its | |
defaultSize | numberInitial size of panel (numeric value between 1-100) | |
id | stringPanel id (unique within group); falls back to | |
maxSize | numberThe maximum allowable size of panel (numeric value between 1-100); defaults to | |
minSize | numberThe minimum allowable size of panel (numeric value between 1-100); defaults to | |
order | numberThe order of panel within group; required for groups with conditionally rendered panels |
| Emit | Payload |
|---|---|
collapse | []Event handler called when panel is collapsed. |
expand | []Event handler called when panel is expanded. |
resize | [size: number, prevSize: number]Event handler called when panel is resized; size parameter is a numeric value between 1-100. |
| Slots (default) | Payload |
|---|---|
isCollapsed | booleanIs the panel collapsed |
isExpanded | booleanIs the panel expanded |
| Methods | Type |
|---|---|
collapse | () => voidIf panel is |
expand | () => voidIf panel is currently collapsed, expand it to its most recent size. |
getSize | () => numberGets the current size of the panel as a percentage (1 - 100). |
resize | (size: number) => voidResize panel to the specified percentage (1 - 100). |
Resize Handle
Handle that use for resizing.
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwrite by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
disabled | booleanDisable drag handle | |
hitAreaMargins | PointerHitAreaMarginsAllow this much margin when determining resizable handle hit detection | |
id | stringResize handle id (unique within group); falls back to | |
tabindex | 0 | numberTabindex for the handle |
| Emit | Payload |
|---|---|
dragging | [isDragging: boolean]Event handler called when dragging the handler. |
| Data Attribute | Value |
|---|---|
[data-state] | "drag" | "hover" | "inactive" |
[data-disabled] | Present when disabled |
[data-orientation] | "vertical" | "horizontal" |
Examples
Collapsible
Use the collapsible prop to allow the panel to collapse into collapsedSize when minSize is reached.
(collapsedSize and minSize props are required.)
<template>
<SplitterGroup>
<SplitterPanel
collapsible
:collapsed-size="10"
:min-size="35"
>
Panel A
</SplitterPanel>
<SplitterResizeHandle />
<SplitterPanel>
Panel B
</SplitterPanel>
</SplitterGroup>
</template>Persist in localStorage
Use the autoSaveId prop to save the layout data into localStorage.
<template>
<SplitterGroup auto-save-id="any-id">
…
</SplitterGroup>
</template>Persist layout with SSR
By default, Splitter uses localStorage to persist layouts. With server rendering, this can cause a flicker when the default layout (rendered on the server) is replaced with the persisted layout (in localStorage). The way to avoid this flicker is to also persist the layout with a cookie like so:
<!-- with Nuxt -->
<script setup lang="ts">
const layout = useCookie<number[]>('splitter:layout')
</script>
<template>
<SplitterGroup
direction="horizontal"
@layout="layout = $event"
>
<SplitterPanel :default-size="layout[0]">
…
</SplitterPanel>
<SplitterResizeHandle />
<SplitterPanel :default-size="layout[1]">
…
</SplitterPanel>
</SplitterGroup>
</template>Collapse/Expand programmatically
Sometimes panels need to resize or collapse/expand in response to user actions. SplitterPanel exposes the collapse and expand methods to achieve this.
<script setup lang="ts">
const panelRef = ref<InstanceType<typeof SplitterPanel>>()
</script>
<template>
<button
@click="panelRef?.isCollapsed ? panelRef?.expand() : panelRef?.collapse() "
>
{{ panelRef?.isCollapsed ? 'Expand' : 'Collapse' }}
</button>
<SplitterGroup>
<SplitterPanel
ref="panelRef"
collapsible
:collapsed-size="10"
:min-size="35"
>
…
</SplitterPanel>
<SplitterResizeHandle />
<SplitterPanel>
…
</SplitterPanel>
</SplitterGroup>
</template>Custom handle
Customize the handle by passing any element as the slot.
<template>
<SplitterGroup>
<SplitterPanel>
…
</SplitterPanel>
<SplitterResizeHandle>
<Icon icon="radix-icons-drag-handle-dots-2" />
</SplitterResizeHandle>
<SplitterPanel>
…
</SplitterPanel>
</SplitterGroup>
</template>SSR
Splitter component heavily relies on unique id, however for Vue<3.4 we don't have a reliable way of generating SSR-friendly id.
Thus, if you are using Nuxt or other SSR framework, you are required to manually add the id for all Splitter components. Alternatively, you can wrap the component with <ClientOnly>.
<template>
<SplitterGroup id="group-1">
<SplitterPanel id="group-1-panel-1">
…
</SplitterPanel>
<SplitterResizeHandle id="group-1-resize-1">
<Icon icon="radix-icons-drag-handle-dots-2" />
</SplitterResizeHandle>
<SplitterPanel id="group-1-panel-2">
…
</SplitterPanel>
</SplitterGroup>
</template>Accessibility
Adheres to the Window Splitter WAI-ARIA design pattern.
Keyboard Interactions
| Key | Description |
|---|---|
Enter | If the primary pane is not collapsed, collapses the pane. If the pane is collapsed, restores the splitter to its previous position. |
ArrowDown | Moves a horizontal splitter down. |
ArrowUp | Moves a horizontal splitter up. |
ArrowRight | Moves a vertical splitter to the right. |
ArrowLeft | Moves a vertical splitter to the left. |
Home | Moves splitter to the position that gives the primary pane its smallest allowed size. |
End | Moves splitter to the position that gives the primary pane its largest allowed size. |
