Build faster with Premium Chakra UI Components 💎

Learn more
Skip to Content
DocsShowcaseBlogGuides
Sponsor

Splitter

The Splitter component allows users to resize panels by dragging a handle between them. It supports horizontal, vertical, multi-panel, controlled, and store-driven configurations.

SourceStorybookRecipeArk
AI TipWant to skip the docs? Use the MCP Server
A
B

Usage

import { Splitter } from "@chakra-ui/react"
<Splitter.Root>
  <Splitter.Panel />
  <Splitter.ResizeTrigger>
    <Splitter.ResizeTriggerSeparator />
    <Splitter.ResizeTriggerIndicator />
  </Splitter.ResizeTrigger>
  <Splitter.Panel />
</Splitter.Root>

Shortcuts

The Splitter component provides shortcuts for common use cases.

SplitterResizeTrigger

The Splitter.ResizeTrigger renders the Splitter.ResizeTriggerSeparator and Splitter.ResizeTriggerIndicator within it by default.

Explicitly writing this:

<Splitter.ResizeTrigger id="a:b" />

is shorthand for the following if you don't need to customize the separator or indicator:

<Splitter.ResizeTrigger id="a:b">
  <Splitter.ResizeTriggerSeparator />
  <Splitter.ResizeTriggerIndicator />
</Splitter.ResizeTrigger>

Examples

Controlled

Use onResize and size props to manage panel sizes programmatically.

<Splitter.Root
  panels={[{ id: "a" }, { id: "b" }]}
  size={sizes}
  onResize={(details) => setSizes(details.size)}
>
  {/* ... */}
</Splitter.Root>
Drag the handle to resize panels
A
B
Panel A: 50.0% | Panel B: 50.0%

Store

An alternative way to control the splitter is to use the RootProvider component and the useSplitter store hook.

This way you can access the splitter state and methods from outside the splitter.

A
B
Size: "50.0%, 50.0"

Vertical

Pass the orientation="vertical" prop to the Splitter.Root component for stacked panels that resize vertically.

A
B

Responsive Orientation

Use the useBreakpointValue hook to change the splitter orientation based on screen size. This example shows a vertical splitter on mobile devices and a horizontal splitter on larger screens.

A
B

Multiple Panels

Create layouts with more than two resizable panels by passing an array of panels to the panels prop of the Splitter.Root component.

A
B
C

Collapsible Panels

Make the panels collapsible and snapped to a specific size by setting the collapsible and collapsedSize properties on a panel in the panels array.

This allows users to snap panels to a defined minimum size.

<Splitter.Root
  defaultSize={[40, 60]}
  panels={[
    { id: "a", collapsible: true, collapsedSize: 5, minSize: 25 },
    { id: "b", minSize: 50 },
  ]}
>
  {/* ... */}
</Splitter.Root>
Drag the resizer to collapse or expand Panel A
A
B

Min/Max Constraints

Set minSize and maxSize on panels to constrain their resizable range and prevent resizing beyond these boundaries.

Drag to resize - Panel A: 20-60%, Panel B: min 40%
A
30.0% (min: 20%, max: 60%)
B
70.0% (min: 40%)

Nested Panels

Here's an example of how to nest splitters inside panels to create more complex layouts. Each nested splitter can have its own orientation, sizes, and behaviors independent of the parent splitter.

A
B1
B2

Storage

Set a defaultSize and pair it with a storage solution, such as useLocalStorage, to save users’ panel size preferences. This ensures that panel layouts persist across sessions. Alternatively, you can use cookies or other storage mechanisms depending on your needs.

Drag to resize panels
A
B
LocalStorage [70.0, 50.0]

Disabled Resize

Pass the disabled prop to the Splitter.ResizeTrigger to disable resize on a panel. This is useful if you want certain panels to remain fixed while allowing others to resize.

<Splitter.ResizeTrigger disabled id="a:b" />
A
B

Separator Only

Customize the resize trigger to show only the separator without the indicator. This creates a minimal, clean appearance while maintaining full resize functionality.

<Splitter.ResizeTrigger id="a:b">
  <Splitter.ResizeTriggerSeparator />
</Splitter.ResizeTrigger>
A
B

Reset on Double Click

Use Splitter.Context to access the splitter context and add a double-click handler to the resize trigger. This example resets panel sizes to their default values when the resize handle is double-clicked.

A
B

Resize Events

Track resize events using onResizeStart, onResize, and onResizeEnd props. This example logs all resize events with timestamps and panel sizes, useful for debugging or implementing custom resize behavior.

Drag the handle to resize panels
A
B
Resize events will appear here...

Keyboard Resize

The Splitter supports keyboard-based resizing for accessibility and precise control:

  • Press Tab until the resize handle is focused.
  • Use Arrow keys to resize panels.
  • Hold Shift for larger steps.
  • Press Home / End to jump to minimum or maximum sizes.
  • Control the step size using the keyboardResizeBy prop.
Focus the resize handle and use arrow keys
A
B

Conditional Rendering

This example shows a horizontal splitter where panels can be shown or hidden dynamically. Use the buttons above the splitter to toggle the left and right panels - perfect for layouts where certain sections may not always be needed.

The splitter automatically adjusts the remaining panels when one is hidden, keeping everything responsive. Initial panel sizes are set with defaultSize, and minSize ensures panels never shrink too small.

left
center
right

Dynamic Panels

Add or remove panels dynamically while maintaining relative proportions. This example demonstrates how to manage panel state and redistribute sizes when panels are added or removed.

2 panels
a
b

Composition

A real-world VS Code-like layout demonstrating nested splitters with different orientations, collapsible panels, and integrated code editing.

src
App.tsx
index.tsx
package.json
App.tsx
import { useState } from "react"
  
  export const Counter = () => {
    const [count, setCount] = useState(0)
  
    return (
      <div>
        <p>Count: {count}</p>
        <button onClick={() => setCount(count + 1)}>
          Increment
        </button>
      </div>
    )
  }
Terminal
$ npm run dev
  
  > dev@1.0.0 dev
  > vite
  
    VITE v5.0.0  ready in 234 ms
  
    ➜  Local:   http://localhost:5173/
    ➜  Network: use --host to expose
    ➜  press h + enter to show help

Guides

Splitter Context

When you need to programmatically control the splitter, you can access the splitter context and its methods in two ways:

  • using the Splitter.Context render prop
  • using the useSplitterContext hook

Splitter.Context Render Prop

Use Splitter.Context as a render prop to access the context within the component tree:

<Splitter.Root defaultSize={[50, 50]} panels={[{ id: "a" }, { id: "b" }]}>
  <Splitter.Panel id="a">Panel A</Splitter.Panel>

  <Splitter.Context>
    {(context) => (
      <Splitter.ResizeTrigger
        id="a:b"
        onDoubleClick={() => {
          context.resetSizes()
        }}
      />
    )}
  </Splitter.Context>

  <Splitter.Panel id="b">Panel B</Splitter.Panel>
</Splitter.Root>

useSplitterContext Hook

Alternatively, use the useSplitterContext hook in a child component:

import { useSplitterContext } from "@chakra-ui/react"

const ResetButton = () => {
  const splitter = useSplitterContext()
  return <button onClick={() => splitter.resetSizes()}>Reset Sizes</button>
}

const Demo = () => (
  <Splitter.Root defaultSize={[50, 50]} panels={[{ id: "a" }, { id: "b" }]}>
    <Splitter.Panel id="a">Panel A</Splitter.Panel>
    <Splitter.ResizeTrigger id="a:b" />
    <Splitter.Panel id="b">
      <ResetButton />
    </Splitter.Panel>
  </Splitter.Root>
)

The context object (from either method) includes:

  • resetSizes(): Reset all panels to their default sizes
  • setSize(sizes): Set panel sizes programmatically
  • collapsePanel(id): Collapse a specific panel
  • expandPanel(id): Expand a collapsed panel
  • isPanelCollapsed(id): Check if a panel is collapsed
  • getItems(): Get the current items (panels and handles)
  • size: Current panel sizes array

Props

Root

PropDefaultType
panels *
PanelData[]

The size constraints of the panels.

orientation 'horizontal'
'horizontal' | 'vertical'

The orientation of the splitter. Can be `horizontal` or `vertical`

as
React.ElementType

The underlying element to render.

asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.
unstyled
boolean

Whether to remove the component's style.

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.

size
number[]

The controlled size data of the panels

Panel

PropDefaultType
id *
string

as
React.ElementType

The underlying element to render.

asChild
boolean

Use the provided child element as the default rendered element, combining their props and behavior.

For more details, read our Composition guide.

ResizeTrigger

PropDefaultType
id *
`${string}:${string}`

as
React.ElementType

The underlying element to render.

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

Explorer

Explore the Splitter component parts interactively. Click on parts in the sidebar to highlight them in the preview.

A
B

Component Anatomy

Hover to highlight, click to select parts

root

panel

resizeTrigger

resizeTriggerIndicator

resizeTriggerSeparator

splitter.recipe.ts

Previous

SimpleGrid

Next

Stack