Skip to main content
View Zag.js on Github
Join the Discord server

Splitter

A splitter allow create dynamic layouts split into vertically or horizontally arranged panes. Panes are separated by the splitter bars that allow dragging to resize or expand/collapse them.

A

B

Properties

Features

  • Built with flexbox for flexible layout and SSR
  • Support both dynamic horizontal and vertical panels
  • Support multiple panels and splitters
  • Support for collapsible panels
  • Support for panel constraints like min and max sizes
  • Programmatic control of panel sizes
  • Implements the Window Splitter pattern for accessibility and keyboard controls

Installation

To use the splitter machine in your project, run the following command in your command line:

npm install @zag-js/splitter @zag-js/react # or yarn add @zag-js/splitter @zag-js/react

This command will install the framework agnostic splitter logic and the reactive utilities for your framework of choice.

Anatomy

To set up the slider 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.

Usage

First, import the splitter package into your project

import * as splitter from "@zag-js/splitter"

The splitter package exports two key functions:

  • machine — The state machine logic for the splitter widget.
  • connect — The function that translates the machine's state to JSX attributes and event handlers.

You'll also need to provide a unique id to the useMachine hook. This is used to ensure that every part has a unique identifier.

Next, import the required hooks and functions for your framework and use the splitter machine in your project 🔥

import * as splitter from "@zag-js/splitter" import { useMachine, normalizeProps } from "@zag-js/react" import { useId } from "react" export function Splitter() { const service = useMachine(splitter.machine, { id: useId(), defaultSize: [ { id: "a", size: 50 }, { id: "b", size: 50 }, ], }) const api = slider.connect(service, normalizeProps) return ( <div {...api.getRootProps()}> <div {...api.getPanelProps({ id: "a" })}> <p>A</p> </div> <div {...api.getResizeTriggerProps({ id: "a:b" })} /> <div {...api.getPanelProps({ id: "b" })}> <p>B</p> </div> </div> ) }

Setting the initial size

To set the initial size of the splitter panels, use the defaultSize property. Ensure the defaultSize totals to 100.

Note: The splitter only supports setting percentage values.

const service = useMachine(splitter.machine, { // ... defaultSize: [40, 60], })

Listening for resize events

When the resize trigger is dragged, the onResize, onResizeStart and onResizeEnd callback is invoked.

const service = useMachine(splitter.machine, { // ... onResize(detail) { console.log("resize", detail) }, onResizeStart(detail) { console.log("change start", detail) }, onResizeEnd(detail) { console.log("change end", detail) }, })

Changing the orientation

By default, the splitter is assumed to be horizontal. To change the orientation to vertical, set the orientation property in the machine's context to vertical.

const service = useMachine(splitter.machine, { // ... orientation: "vertical", })

Specifying constraints

Use the panels property to specify constraints like minSize and maxSize for the splitter panels.

const service = useMachine(splitter.machine, { // ... panels: [ { id: "a", minSize: 100, maxSize: 300 }, { id: "b", minSize: 100, maxSize: 300 }, ], })

Setting the collapsed size

Set the collapsedSize and collapsible of a panel to specify the collapsed size of the panel.

For best results, ensure you also set the minSize of the panel

const service = useMachine(splitter.machine, { // ... panels: [ { id: "a", collapsible: true, collapsedSize: 5, minSize: 10, maxSize: 20 }, { id: "b", minSize: 50 }, ], })

This allows the user to drag the splitter to collapse the panel to the collapsedSize.

Listening for collapse events

When the splitter panel is collapsed, the onCollapse callback is invoked. Alternatively, the onExpand callback is invoked when the panel is expanded.

const service = useMachine(splitter.machine, { // ... onCollapse(detail) { console.log("collapse", detail) }, onExpand(detail) { console.log("expand", detail) }, })

Styling guide

Earlier, we mentioned that each accordion part has a data-part attribute added to them to select and style them in the DOM.

Resize trigger

When an splitter item is horizontal or vertical, a data-state attribute is set on the item and content elements.

[data-scope="splitter"][data-part="resize-trigger"] { /* styles for the item */ } [data-scope="splitter"][data-part="resize-trigger"][data-orientation="horizontal"] { /* styles for the item is horizontal state */ } [data-scope="splitter"][data-part="resize-trigger"][data-orientation="vertical"] { /* styles for the item is horizontal state */ } [data-scope="splitter"][data-part="resize-trigger"][data-focus] { /* styles for the item is focus state */ } [data-scope="splitter"][data-part="resize-trigger"]:active { /* styles for the item is active state */ } [data-scope="splitter"][data-part="resize-trigger"][data-disabled] { /* styles for the item is disabled state */ }

Methods and Properties

The splitter's api exposes the following methods and properties:

Machine Context

The splitter machine exposes the following context properties:

  • orientation"horizontal" | "vertical"The orientation of the splitter. Can be `horizontal` or `vertical`
  • sizenumber[]The controlled size data of the panels
  • defaultSizenumber[]The initial size of the panels when rendered. Use when you don't need to control the size of the panels.
  • panelsPanelData[]The size constraints of the panels.
  • onResize(details: ResizeDetails) => voidFunction called when the splitter is resized.
  • onResizeStart() => voidFunction called when the splitter resize starts.
  • onResizeEnd(details: ResizeEndDetails) => voidFunction called when the splitter resize ends.
  • idsPartial<{ 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.
  • keyboardResizeBynumberThe number of pixels to resize the panel by when the keyboard is used.
  • noncestringThe nonce for the injected splitter cursor stylesheet.
  • onCollapse(details: ExpandCollapseDetails) => voidFunction called when a panel is collapsed.
  • onExpand(details: ExpandCollapseDetails) => voidFunction called when a panel is expanded.
  • dir"ltr" | "rtl"The document's text/writing direction.
  • idstringThe unique identifier of the machine.
  • getRootNode() => ShadowRoot | Node | DocumentA root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.

Machine API

The splitter api exposes the following methods:

  • draggingbooleanWhether the splitter is currently being resized.
  • getSizes() => number[]The current sizes of the panels.
  • setSizes(size: number[]) => voidSet the sizes of the panels.
  • getItems() => SplitterItem[]Get the items of the splitter.
  • getPanelSize(id: string) => numberGet the size of a panel.
  • isPanelCollapsed(id: string) => booleanWhether a panel is collapsed.
  • isPanelExpanded(id: string) => booleanWhether a panel is expanded.
  • collapsePanel(id: string) => voidCollapse a panel.
  • expandPanel(id: string, minSize?: number) => voidExpand a panel.
  • resizePanel(id: string, unsafePanelSize: number) => voidResize a panel.
  • getLayout() => stringGet the layout of the splitter.

Data Attributes

Root
data-scope
splitter
data-part
root
data-orientation
The orientation of the splitter
Panel
data-scope
splitter
data-part
panel
data-orientation
The orientation of the panel
data-index
The index of the item
ResizeTrigger
data-scope
splitter
data-part
resize-trigger
data-orientation
The orientation of the resizetrigger
data-focus
Present when focused
data-disabled
Present when disabled

Edit this page on GitHub

Proudly made in🇳🇬by Segun Adebayo

Copyright © 2025
On this page