Splitter
A component that divides your interface into resizable sections
Anatomy
To set up the splitter correctly, you'll need to understand its anatomy and how we name its parts.
Each part includes a
data-part
attribute to help identify them in the DOM.
Examples
Learn how to use the Splitter
component in your project. Let's take a look at the most basic example:
import { Splitter } from '@ark-ui/react/splitter'
export const Basic = () => (
<Splitter.Root panels={[{ id: 'a' }, { id: 'b' }]}>
<Splitter.Panel id="a">A</Splitter.Panel>
<Splitter.ResizeTrigger id="a:b" aria-label="Resize" />
<Splitter.Panel id="b">B</Splitter.Panel>
</Splitter.Root>
)
import { Splitter } from '@ark-ui/solid/splitter'
export const Basic = () => (
<Splitter.Root panels={[{ id: 'a' }, { id: 'b' }]}>
<Splitter.Panel id="a">A</Splitter.Panel>
<Splitter.ResizeTrigger id="a:b" aria-label="Resize" />
<Splitter.Panel id="b">B</Splitter.Panel>
</Splitter.Root>
)
<script setup lang="ts">
import { Splitter } from '@ark-ui/vue/splitter'
</script>
<template>
<Splitter.Root :panels="[{ id: 'a' }, { id: 'b' }]">
<Splitter.Panel id="a">A</Splitter.Panel>
<Splitter.ResizeTrigger id="a:b" aria-label="Resize" />
<Splitter.Panel id="b">B</Splitter.Panel>
</Splitter.Root>
</template>
Using Render Props
The Splitter component allows you to pass a function as a child to gain direct access to its API. This provides more control and allows you to modify the size of the panels programmatically:
import { Splitter } from '@ark-ui/react/splitter'
export const RenderProp = () => (
<Splitter.Root panels={[{ id: 'a' }, { id: 'b' }]}>
<Splitter.Context>
{(splitter) => (
<>
<Splitter.Panel id="a">
<button type="button" onClick={() => splitter.resizePanel('a', 10)}>
Set to 10%
</button>
</Splitter.Panel>
<Splitter.ResizeTrigger id="a:b" aria-label="Resize" />
<Splitter.Panel id="b">
<button type="button" onClick={() => splitter.resizePanel('b', 10)}>
Set to 10%
</button>
</Splitter.Panel>
</>
)}
</Splitter.Context>
</Splitter.Root>
)
import { Splitter } from '@ark-ui/solid/splitter'
export const RenderProp = () => (
<Splitter.Root defaultSize={[50, 50]} panels={[{ id: 'a' }, { id: 'b' }]}>
<Splitter.Context>
{(api) => (
<>
<Splitter.Panel id="a">
<button type="button" onClick={() => api().resizePanel('a', 10)}>
Set to 10%
</button>
</Splitter.Panel>
<Splitter.ResizeTrigger id="a:b" aria-label="Resize" />
<Splitter.Panel id="b">
<button type="button" onClick={() => api().resizePanel('b', 10)}>
Set to 10%
</button>
</Splitter.Panel>
</>
)}
</Splitter.Context>
</Splitter.Root>
)
<script setup lang="ts">
import { Splitter } from '@ark-ui/vue/splitter'
</script>
<template>
<Splitter.Root :panels="[{ id: 'a' }, { id: 'b' }]">
<Splitter.Context v-slot="splitter">
<Splitter.Panel id="a">
<button @click="splitter.resizePanel('a', 10)">Set A to 10%</button>
</Splitter.Panel>
<Splitter.ResizeTrigger id="a:b" aria-label="Resize" />
<Splitter.Panel id="b">
<button @click="splitter.resizePanel('b', 10)">Set B to 10%</button>
</Splitter.Panel>
</Splitter.Context>
</Splitter.Root>
</template>
Handling Events
Splitter also provides onResizeStart
, onResize
, and onResizeEnd
events which can be useful to perform some actions
during the start and end of the resizing process:
import { Splitter } from '@ark-ui/react/splitter'
export const Events = () => (
<Splitter.Root
panels={[{ id: 'a' }, { id: 'b' }]}
onResize={(details) => console.log('onResize', details)}
onResizeStart={() => console.log('onResizeStart')}
onResizeEnd={(details) => console.log('onResizeEnd', details)}
onExpand={(details) => console.log('onExpand', details)}
onCollapse={(details) => console.log('onCollapse', details)}
>
<Splitter.Panel id="a">A</Splitter.Panel>
<Splitter.ResizeTrigger id="a:b" aria-label="Resize" />
<Splitter.Panel id="b">B</Splitter.Panel>
</Splitter.Root>
)
import { Splitter } from '@ark-ui/solid/splitter'
export const Events = () => (
<Splitter.Root
panels={[{ id: 'a' }, { id: 'b' }]}
defaultSize={[50, 50]}
onResizeStart={() => console.log('onResizeStart')}
onResizeEnd={(details) => console.log('onResizeEnd', details)}
onExpand={(details) => console.log('onExpand', details)}
onCollapse={(details) => console.log('onCollapse', details)}
>
<Splitter.Panel id="a">A</Splitter.Panel>
<Splitter.ResizeTrigger id="a:b" aria-label="Resize" />
<Splitter.Panel id="b">B</Splitter.Panel>
</Splitter.Root>
)
<script setup lang="ts">
import { Splitter } from '@ark-ui/vue/splitter'
</script>
<template>
<Splitter.Root
:panels="[{ id: 'a' }, { id: 'b' }]"
@resize="(details) => console.log('onResize', details)"
@resize-start="() => console.log('onResizeStart')"
@resize-end="(details) => console.log('onResizeEnd', details)"
@expand="(details) => console.log('onExpand', details)"
@collapse="(details) => console.log('onCollapse', details)"
>
<Splitter.Panel id="a">A</Splitter.Panel>
<Splitter.ResizeTrigger id="a:b" aria-label="Resize" />
<Splitter.Panel id="b">B</Splitter.Panel>
</Splitter.Root>
</template>
Vertical Splitter
By default, the Splitter component is horizontal. If you need a vertical splitter, use the orientation
prop:
import { Splitter } from '@ark-ui/react/splitter'
export const Vertical = () => (
<Splitter.Root orientation="vertical" panels={[{ id: 'a' }, { id: 'b' }]}>
<Splitter.Panel id="a">A</Splitter.Panel>
<Splitter.ResizeTrigger id="a:b" aria-label="Resize" />
<Splitter.Panel id="b">B</Splitter.Panel>
</Splitter.Root>
)
import { Splitter } from '@ark-ui/solid/splitter'
export const Vertical = () => (
<Splitter.Root orientation="vertical" defaultSize={[50, 50]} panels={[{ id: 'a' }, { id: 'b' }]}>
<Splitter.Panel id="a">A</Splitter.Panel>
<Splitter.ResizeTrigger id="a:b" aria-label="Resize" />
<Splitter.Panel id="b">B</Splitter.Panel>
</Splitter.Root>
)
<script setup lang="ts">
import { Splitter } from '@ark-ui/vue/splitter'
</script>
<template>
<Splitter.Root orientation="vertical" :panels="[{ id: 'a' }, { id: 'b' }]">
<Splitter.Panel id="a">A</Splitter.Panel>
<Splitter.ResizeTrigger id="a:b" aria-label="Resize" />
<Splitter.Panel id="b">B</Splitter.Panel>
</Splitter.Root>
</template>
Collapsible Panels
To make a panel collapsible, set the collapsible
prop to true
on the panel you want to make collapsible.
Additionally, you can use the collapsedSize
prop to set the size of the panel when it's collapsed.
This can be useful for building sidebar layouts.
import { Splitter } from '@ark-ui/react/splitter'
export const Collapsible = () => (
<Splitter.Root
defaultSize={[15, 20]}
panels={[
{ id: 'a', collapsible: true, collapsedSize: 5, minSize: 10, maxSize: 20 },
{ id: 'b', minSize: 50 },
]}
>
<Splitter.Panel id="a">A</Splitter.Panel>
<Splitter.ResizeTrigger id="a:b" aria-label="Resize" />
<Splitter.Panel id="b">B</Splitter.Panel>
</Splitter.Root>
)
import { Splitter } from '@ark-ui/solid/splitter'
export const Collapsible = () => (
<Splitter.Root
defaultSize={[15, 20]}
panels={[
{ id: 'a', collapsible: true, collapsedSize: 5, minSize: 10, maxSize: 20 },
{ id: 'b', minSize: 50 },
]}
>
<Splitter.Panel id="a">A</Splitter.Panel>
<Splitter.ResizeTrigger id="a:b" aria-label="Resize" />
<Splitter.Panel id="b">B</Splitter.Panel>
</Splitter.Root>
)
<script setup lang="ts">
import { Splitter } from '@ark-ui/vue/splitter'
</script>
<template>
<Splitter.Root
:default-size="[15, 20]"
:panels="[
{ id: 'a', collapsible: true, collapsedSize: 5, minSize: 10, maxSize: 20 },
{ id: 'b', minSize: 50 },
]"
>
<Splitter.Panel id="a">A</Splitter.Panel>
<Splitter.ResizeTrigger id="a:b" aria-label="Resize" />
<Splitter.Panel id="b">B</Splitter.Panel>
</Splitter.Root>
</template>
Multiple Panels
Here's an example of how to use the Splitter
component with multiple panels.
import { Splitter } from '@ark-ui/react/splitter'
export const MultiplePanels = () => (
<Splitter.Root
panels={[
{ id: 'a', minSize: 20 },
{ id: 'b', minSize: 40 },
{ id: 'c', minSize: 20 },
]}
defaultSize={[20, 60, 20]}
>
<Splitter.Panel id="a">A</Splitter.Panel>
<Splitter.ResizeTrigger id="a:b" aria-label="Resize" />
<Splitter.Panel id="b">B</Splitter.Panel>
<Splitter.ResizeTrigger id="b:c" aria-label="Resize" />
<Splitter.Panel id="c">C</Splitter.Panel>
</Splitter.Root>
)
import { Splitter } from '@ark-ui/solid/splitter'
export const MultiplePanels = () => (
<Splitter.Root
panels={[
{ id: 'a', minSize: 20 },
{ id: 'b', minSize: 40 },
{ id: 'c', minSize: 20 },
]}
defaultSize={[20, 60, 20]}
>
<Splitter.Panel id="a">A</Splitter.Panel>
<Splitter.ResizeTrigger id="a:b" aria-label="Resize" />
<Splitter.Panel id="b">B</Splitter.Panel>
<Splitter.ResizeTrigger id="b:c" aria-label="Resize" />
<Splitter.Panel id="c">C</Splitter.Panel>
</Splitter.Root>
)
<script setup lang="ts">
import { Splitter } from '@ark-ui/vue/splitter'
</script>
<template>
<Splitter.Root
:panels="[
{ id: 'a', minSize: 20 },
{ id: 'b', minSize: 40 },
{ id: 'c', minSize: 20 },
]"
:default-size="[20, 60, 20]"
>
<Splitter.Panel id="a">A</Splitter.Panel>
<Splitter.ResizeTrigger id="a:b" aria-label="Resize" />
<Splitter.Panel id="b">B</Splitter.Panel>
<Splitter.ResizeTrigger id="b:c" aria-label="Resize" />
<Splitter.Panel id="c">C</Splitter.Panel>
</Splitter.Root>
</template>
Using the Root Provider
The RootProvider
component provides a context for the splitter. It accepts the value of the useSplitter
hook. You
can leverage it to access the component state and methods from outside the splitter.
import { Splitter, useSplitter } from '@ark-ui/react/splitter'
export const RootProvider = () => {
const splitter = useSplitter({ defaultSize: [50, 50], panels: [{ id: 'a' }, { id: 'b' }] })
return (
<>
<button onClick={() => splitter.setSizes([100, 0])}>Maximize a</button>
<Splitter.RootProvider value={splitter}>
<Splitter.Panel id="a">A</Splitter.Panel>
<Splitter.ResizeTrigger id="a:b" aria-label="Resize" />
<Splitter.Panel id="b">B</Splitter.Panel>
</Splitter.RootProvider>
</>
)
}
import { Splitter, useSplitter } from '@ark-ui/solid/splitter'
export const RootProvider = () => {
const splitter = useSplitter({ defaultSize: [50, 50], panels: [{ id: 'a' }, { id: 'b' }] })
return (
<>
<button onClick={() => splitter().setSizes([100, 0])}>Maximize a</button>
<Splitter.RootProvider value={splitter}>
<Splitter.Panel id="a">A</Splitter.Panel>
<Splitter.ResizeTrigger id="a:b" aria-label="Resize" />
<Splitter.Panel id="b">B</Splitter.Panel>
</Splitter.RootProvider>
</>
)
}
<script setup lang="ts">
import { Splitter, useSplitter } from '@ark-ui/vue/splitter'
const splitter = useSplitter({
defaultSize: [50, 50],
panels: [{ id: 'a' }, { id: 'b' }],
})
</script>
<template>
<button @click="splitter.setSizes([100, 0])">Maximize a</button>
<Splitter.RootProvider :value="splitter">
<Splitter.Panel id="a">A</Splitter.Panel>
<Splitter.ResizeTrigger id="a:b" aria-label="Resize" />
<Splitter.Panel id="b">B</Splitter.Panel>
</Splitter.RootProvider>
</template>
If you're using the
RootProvider
component, you don't need to use theRoot
component.
API Reference
Root
Prop | Default | Type |
---|---|---|
panels | PanelData[] The size constraints of the panels. | |
asChild | boolean Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
defaultSize | number[] The initial size of the panels when rendered. Use when you don't need to control the size of the panels. | |
id | string The unique identifier of the machine. | |
ids | Partial<{
root: string
resizeTrigger(id: string): string
label(id: string): string
panel(id: string | number): string
}> The ids of the elements in the splitter. Useful for composition. | |
keyboardResizeBy | number The number of pixels to resize the panel by when the keyboard is used. | |
nonce | string The nonce for the injected splitter cursor stylesheet. | |
onCollapse | (details: ExpandCollapseDetails) => void Function called when a panel is collapsed. | |
onExpand | (details: ExpandCollapseDetails) => void Function called when a panel is expanded. | |
onResize | (details: ResizeDetails) => void Function called when the splitter is resized. | |
onResizeEnd | (details: ResizeEndDetails) => void Function called when the splitter resize ends. | |
onResizeStart | () => void Function called when the splitter resize starts. | |
orientation | 'horizontal' | 'horizontal' | 'vertical' The orientation of the splitter. Can be `horizontal` or `vertical` |
size | number[] The controlled size data of the panels |
Data Attribute | Value |
---|---|
[data-scope] | splitter |
[data-part] | root |
[data-orientation] | The orientation of the splitter |
Panel
Prop | Default | Type |
---|---|---|
id | string | |
asChild | boolean Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Data Attribute | Value |
---|---|
[data-scope] | splitter |
[data-part] | panel |
[data-orientation] | The orientation of the panel |
[data-id] | |
[data-index] | The index of the item |
ResizeTrigger
Prop | Default | Type |
---|---|---|
id | `${string}:${string}` | |
asChild | boolean Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
disabled | boolean |
Data Attribute | Value |
---|---|
[data-scope] | splitter |
[data-part] | resize-trigger |
[data-id] | |
[data-orientation] | The orientation of the resizetrigger |
[data-focus] | Present when focused |
[data-disabled] | Present when disabled |
RootProvider
Prop | Default | Type |
---|---|---|
value | UseSplitterReturn | |
asChild | boolean Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Accessibility
Complies with the Window Splitter WAI-ARIA design pattern.