{"slug":"splitter","title":"Splitter","description":"Using the splitter machine in your project.","contentType":"component","framework":"vue","content":"A splitter creates resizable layouts with horizontal or vertical panels.\n\n## Resources\n\n\n[Latest version: v1.39.1](https://www.npmjs.com/package/@zag-js/splitter)\n[Logic Visualizer](https://zag-visualizer.vercel.app/splitter)\n[Source Code](https://github.com/chakra-ui/zag/tree/main/packages/machines/splitter)\n\n\n\n**Features**\n\n- Built with flexbox for flexible layout and SSR\n- Supports horizontal and vertical panels\n- Supports multiple panels and resize handles\n- Supports collapsible panels\n- Supports panel constraints like min and max sizes\n- Programmatic control of panel sizes\n- Implements the\n  [Window Splitter pattern](https://www.w3.org/WAI/ARIA/apg/patterns/windowsplitter/)\n  for accessibility and keyboard controls\n- Supports multi-drag at handle intersections via a shared registry\n\n## Installation\n\nInstall the splitter package:\n\n```bash\nnpm install @zag-js/splitter @zag-js/vue\n# or\nyarn add @zag-js/splitter @zag-js/vue\n```\n\n## Anatomy\n\nCheck the splitter anatomy and part names.\n\n> Each part includes a `data-part` attribute to help identify them in the DOM.\n\n\n\n## Usage\n\nImport the splitter package:\n\n```tsx\nimport * as splitter from \"@zag-js/splitter\"\n```\n\nThe splitter package exports two key functions:\n\n- `machine` - State machine logic.\n- `connect` - Maps machine state to JSX props and event handlers.\n\nThen use the framework integration helpers:\n\n```html\n<script setup>\n  import * as splitter from \"@zag-js/splitter\"\n  import { normalizeProps, useMachine } from \"@zag-js/vue\"\n  import { computed } from \"vue\"\n\n  const service = useMachine(splitter.machine, {\n    id: \"1\",\n    defaultSize: [80, 20],\n    panels: [\n      { id: \"a\", minSize: 10 },\n      { id: \"b\", minSize: 10 },\n    ],\n  })\n\n  const api = computed(() => splitter.connect(service, normalizeProps))\n</script>\n\n<template>\n  <div v-bind=\"api.getRootProps()\">\n    <div v-bind=\"api.getPanelProps({ id: 'a' })\">\n      <p>A</p>\n    </div>\n    <div v-bind=\"api.getResizeTriggerProps({ id: 'a:b' })\" />\n    <div v-bind=\"api.getPanelProps({ id: 'b' })\">\n      <p>B</p>\n    </div>\n  </div>\n</template>\n```\n\n### Setting the initial size\n\nTo set the initial size of the splitter panels, use the `defaultSize` property.\nEnsure the `defaultSize` totals to `100`.\n\n> Note: The splitter only supports setting percentage values.\n\n```tsx {3}\nconst service = useMachine(splitter.machine, {\n  // ...\n  defaultSize: [40, 60],\n})\n```\n\n### Controlled panel sizes\n\nUse `size` and `onResize` for controlled layouts.\n\n```tsx\nconst service = useMachine(splitter.machine, {\n  panels,\n  size,\n  onResize(details) {\n    setSize(details.size)\n  },\n})\n```\n\n### Listening for resize events\n\nWhen the resize trigger is dragged, the `onResize`, `onResizeStart` and\n`onResizeEnd` callbacks are invoked.\n\n```tsx {3-10}\nconst service = useMachine(splitter.machine, {\n  // ...\n  onResize(detail) {\n    console.log(\"resize\", detail)\n  },\n  onResizeStart() {\n    console.log(\"resize start\")\n  },\n  onResizeEnd(detail) {\n    console.log(\"change end\", detail)\n  },\n})\n```\n\n### Changing the orientation\n\nBy default, the splitter is assumed to be horizontal. To change the orientation\nto vertical, set the `orientation` property in the machine's context to\n`vertical`.\n\n```tsx {3}\nconst service = useMachine(splitter.machine, {\n  // ...\n  orientation: \"vertical\",\n})\n```\n\n## Specifying constraints\n\nUse the `panels` property to specify constraints like `minSize` and `maxSize`\nfor the splitter panels.\n\n```tsx {3-6}\nconst service = useMachine(splitter.machine, {\n  // ...\n  panels: [\n    { id: \"a\", minSize: 20, maxSize: 80 },\n    { id: \"b\", minSize: 20, maxSize: 80 },\n  ],\n})\n```\n\n### Configuring keyboard resize step\n\nUse `keyboardResizeBy` to control how many pixels arrow keys resize by.\n\n```tsx\nconst service = useMachine(splitter.machine, {\n  panels,\n  keyboardResizeBy: 16,\n})\n```\n\n### Setting the collapsed size\n\nSet the `collapsedSize` and `collapsible` of a panel to specify the collapsed\nsize of the panel.\n\n> For best results, ensure you also set the `minSize` of the panel\n\n```tsx {4}\nconst service = useMachine(splitter.machine, {\n  // ...\n  panels: [\n    { id: \"a\", collapsible: true, collapsedSize: 5, minSize: 10, maxSize: 20 },\n    { id: \"b\", minSize: 50 },\n  ],\n})\n```\n\nThis allows the user to drag the splitter to collapse the panel to the\n`collapsedSize`.\n\n### Listening for collapse events\n\nWhen the splitter panel is collapsed, the `onCollapse` callback is invoked.\nAlternatively, the `onExpand` callback is invoked when the panel is expanded.\n\n```tsx {3-8}\nconst service = useMachine(splitter.machine, {\n  // ...\n  onCollapse(detail) {\n    console.log(\"collapse\", detail)\n  },\n  onExpand(detail) {\n    console.log(\"expand\", detail)\n  },\n})\n```\n\n### Programmatic panel control\n\nUse the connected API to resize, collapse, or expand panels from code.\n\n```tsx\napi.setSizes([30, 70])\napi.resizePanel(\"a\", 40)\napi.collapsePanel(\"a\")\napi.expandPanel(\"a\")\napi.resetSizes()\n```\n\n## Multi-drag with registry\n\nWhen you have nested splitters (e.g. horizontal and vertical), users can drag at\nhandle intersections to resize both directions simultaneously. Use\n`splitter.registry()` to coordinate multiple splitter instances.\n\n```tsx\nimport * as splitter from \"@zag-js/splitter\"\n\n// Create a shared registry (once, at the layout level)\nconst registry = splitter.registry()\n```\n\nPass the `registry` to each splitter machine that should participate in\nmulti-drag:\n\n```tsx\nconst horizontalService = useMachine(splitter.machine, {\n  panels: [{ id: \"left\" }, { id: \"right\" }],\n  registry,\n})\n\nconst verticalService = useMachine(splitter.machine, {\n  orientation: \"vertical\",\n  panels: [{ id: \"top\" }, { id: \"bottom\" }],\n  registry,\n})\n```\n\nWhen a user drags near the intersection of two resize handles, the registry\ndetects both handles and resizes them together. The registry also manages the\ncursor globally during intersection dragging.\n\n### Registry options\n\nThe `splitter.registry()` function accepts optional configuration:\n\n```tsx\nconst registry = splitter.registry({\n  // Nonce for injected cursor stylesheet (CSP compliance)\n  nonce: \"abc123\",\n  // Hit area margins for intersection detection\n  hitAreaMargins: {\n    coarse: 20, // touch devices (default: 15)\n    fine: 10, // pointer devices (default: 5)\n  },\n})\n```\n\n## Styling guide\n\nEach part includes a `data-part` attribute you can target in CSS.\n\n### Resize trigger\n\nWhen a resize trigger is horizontal or vertical, a `data-orientation` attribute\nis set on the trigger element.\n\n```css\n[data-scope=\"splitter\"][data-part=\"resize-trigger\"] {\n  /* styles for the item */\n}\n\n[data-scope=\"splitter\"][data-part=\"resize-trigger\"][data-orientation=\"horizontal\"] {\n  /* styles for the item is horizontal state */\n}\n\n[data-scope=\"splitter\"][data-part=\"resize-trigger\"][data-orientation=\"vertical\"] {\n  /* styles for the item is horizontal state */\n}\n\n[data-scope=\"splitter\"][data-part=\"resize-trigger\"][data-focus] {\n  /* styles for the item is focus state */\n}\n\n[data-scope=\"splitter\"][data-part=\"resize-trigger\"]:active {\n  /* styles for the item is active state */\n}\n\n[data-scope=\"splitter\"][data-part=\"resize-trigger\"][data-disabled] {\n  /* styles for the item is disabled state */\n}\n```\n\n## Methods and Properties\n\nThe splitter's `api` exposes the following methods and properties:\n\n### Machine Context\n\nThe splitter machine exposes the following context properties:\n\n**`orientation`**\nType: `\"horizontal\" | \"vertical\"`\nDescription: The orientation of the splitter. Can be `horizontal` or `vertical`\n\n**`size`**\nType: `number[]`\nDescription: The controlled size data of the panels\n\n**`defaultSize`**\nType: `number[]`\nDescription: The initial size of the panels when rendered.\nUse when you don't need to control the size of the panels.\n\n**`panels`**\nType: `PanelData[]`\nDescription: The size constraints of the panels.\n\n**`onResize`**\nType: `(details: ResizeDetails) => void`\nDescription: Function called when the splitter is resized.\n\n**`onResizeStart`**\nType: `() => void`\nDescription: Function called when the splitter resize starts.\n\n**`onResizeEnd`**\nType: `(details: ResizeEndDetails) => void`\nDescription: Function called when the splitter resize ends.\n\n**`ids`**\nType: `Partial<{ root: string; resizeTrigger: (id: string) => string; label: (id: string) => string; panel: (id: string | number) => string; }>`\nDescription: The ids of the elements in the splitter. Useful for composition.\n\n**`keyboardResizeBy`**\nType: `number`\nDescription: The number of pixels to resize the panel by when the keyboard is used.\n\n**`nonce`**\nType: `string`\nDescription: The nonce for the injected splitter cursor stylesheet.\n\n**`onCollapse`**\nType: `(details: ExpandCollapseDetails) => void`\nDescription: Function called when a panel is collapsed.\n\n**`onExpand`**\nType: `(details: ExpandCollapseDetails) => void`\nDescription: Function called when a panel is expanded.\n\n**`registry`**\nType: `SplitterRegistry`\nDescription: The splitter registry to use for multi-drag support.\nWhen provided, enables dragging at the intersection of multiple splitters.\n\n**`dir`**\nType: `\"ltr\" | \"rtl\"`\nDescription: The document's text/writing direction.\n\n**`id`**\nType: `string`\nDescription: The unique identifier of the machine.\n\n**`getRootNode`**\nType: `() => ShadowRoot | Node | Document`\nDescription: A root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.\n\n### Machine API\n\nThe splitter `api` exposes the following methods:\n\n**`dragging`**\nType: `boolean`\nDescription: Whether the splitter is currently being resized.\n\n**`orientation`**\nType: `\"horizontal\" | \"vertical\"`\nDescription: The orientation of the splitter.\n\n**`getSizes`**\nType: `() => number[]`\nDescription: Returns the current sizes of the panels.\n\n**`setSizes`**\nType: `(size: number[]) => void`\nDescription: Sets the sizes of the panels.\n\n**`getItems`**\nType: `() => SplitterItem[]`\nDescription: Returns the items of the splitter.\n\n**`getPanels`**\nType: `() => PanelData[]`\nDescription: Returns the panels of the splitter.\n\n**`getPanelById`**\nType: `(id: string) => PanelData`\nDescription: Returns the panel with the specified id.\n\n**`getPanelSize`**\nType: `(id: string) => number`\nDescription: Returns the size of the specified panel.\n\n**`isPanelCollapsed`**\nType: `(id: string) => boolean`\nDescription: Returns whether the specified panel is collapsed.\n\n**`isPanelExpanded`**\nType: `(id: string) => boolean`\nDescription: Returns whether the specified panel is expanded.\n\n**`collapsePanel`**\nType: `(id: string) => void`\nDescription: Collapses the specified panel.\n\n**`expandPanel`**\nType: `(id: string, minSize?: number) => void`\nDescription: Expands the specified panel.\n\n**`resizePanel`**\nType: `(id: string, unsafePanelSize: number) => void`\nDescription: Resizes the specified panel.\n\n**`getLayout`**\nType: `() => string`\nDescription: Returns the layout of the splitter.\n\n**`resetSizes`**\nType: `VoidFunction`\nDescription: Resets the splitter to its initial state.\n\n**`getResizeTriggerState`**\nType: `(props: ResizeTriggerProps) => ResizeTriggerState`\nDescription: Returns the state of the resize trigger.\n\n### Data Attributes\n\n**`Root`**\n\n**`data-scope`**: splitter\n**`data-part`**: root\n**`data-orientation`**: The orientation of the splitter\n**`data-dragging`**: Present when in the dragging state\n\n**`Panel`**\n\n**`data-scope`**: splitter\n**`data-part`**: panel\n**`data-orientation`**: The orientation of the panel\n**`data-dragging`**: Present when in the dragging state\n**`data-id`**: \n**`data-index`**: The index of the item\n\n**`ResizeTrigger`**\n\n**`data-scope`**: splitter\n**`data-part`**: resize-trigger\n**`data-id`**: \n**`data-orientation`**: The orientation of the resizetrigger\n**`data-focus`**: Present when focused\n**`data-dragging`**: Present when in the dragging state\n**`data-disabled`**: Present when disabled","package":"@zag-js/splitter","editUrl":"https://github.com/chakra-ui/zag/edit/main/website/data/components/splitter.mdx"}