Skip to content
Destyler UI Destyler UI Destyler UI

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.

One

Two

One

Two

One

Two

One

Two

Features

Install

Install the component from your command line.

Terminal window
      
        
npm install @destyler/splitter @destyler/vue
Terminal window
      
        
npm install @destyler/splitter @destyler/react
Terminal window
      
        
npm install @destyler/splitter @destyler/svelte
Terminal window
      
        
npm install @destyler/splitter @destyler/solid

Anatomy

Import all parts and piece them together.

<script setup lang="ts">
import * as splitter from "@destyler/splitter"
import { normalizeProps, useMachine } from "@destyler/vue"
import { computed,useId } from "vue"
const [state, send] = useMachine(
splitter.machine({
id: useId(),
})
)
const api = computed(() => splitter.connect(state.value, send, normalizeProps))
</script>
<template>
<div v-bind="api.getRootProps()">
<div v-bind="api.getPanelProps({ id: 'a' })">
</div>
<div v-bind="api.getResizeTriggerProps({ id: 'a:b' })" />
<div v-bind="api.getPanelProps({ id: 'b' })">
</div>
</div>
</template>
import { normalizeProps, useMachine } from '@destyler/react'
import * as splitter from '@destyler/splitter'
import { useId } from 'react'
export default function SplitterDemo() {
const [state, send] = useMachine(
splitter.machine({
id: useId(),
})
)
const api = splitter.connect(state, send, normalizeProps)
return (
<>
<div {...api.getRootProps()}>
<div {...api.getPanelProps({ id: 'a' })}></div>
<div {...api.getResizeTriggerProps({ id: 'a:b' })}></div>
<div {...api.getPanelProps({ id: 'b' })}></div>
</div>
</>
)
}
<script lang="ts">
import * as splitter from "@destyler/splitter"
import { normalizeProps, useMachine } from "@destyler/svelte"
const [state, send] = useMachine(
splitter.machine({
id: crypto.randomUUID(),
})
)
const api = $derived(splitter.connect(state, send, normalizeProps))
</script>
<div {...api.getRootProps()}>
<div {...api.getPanelProps({ id: 'a' })}></div>
<div {...api.getResizeTriggerProps({ id: 'a:b' })}></div>
<div {...api.getPanelProps({ id: 'b' })}></div>
</div>
import { normalizeProps, useMachine } from '@destyler/solid'
import * as splitter from '@destyler/splitter'
import { createMemo, createUniqueId } from 'solid-js'
export default function SplitterDemo() {
const [state, send] = useMachine(
splitter.machine({
id: createUniqueId(),
})
)
const api = createMemo(() => splitter.connect(state, send, normalizeProps))
return (
<>
<div {...api().getRootProps()}>
<div {...api().getPanelProps({ id: 'a' })}></div>
<div {...api().getResizeTriggerProps({ id: 'a:b' })}></div>
<div {...api().getPanelProps({ id: 'b' })}></div>
</div>
</>
)
}

Listening for events

When the resize trigger of splitter changes, the onSizeChangeStart and onSizeChangeEnd callback is invoked.

const [state, send] = useMachine(
splitter.machine({
onSizeChangeStart(detail) {
console.log("change start", detail)
},
onSizeChangeEnd(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 [state, send] = useMachine(
splitter.machine({
orientation: 'vertical',
}),
)

Styling guide

Earlier, we mentioned that each splitter 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

Machine Context

The splitter machine exposes the following context properties:

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.
orientation
"horizontal" | "vertical"
The orientation of the splitter. Can be `horizontal` or `vertical`
size
PanelSizeData[]
The size data of the panels
onSizeChange
(details: SizeChangeDetails) => void
Function called when the splitter is resized.
onSizeChangeEnd
(details: SizeChangeDetails) => void
Function called when the splitter resize ends.
getRootNode
() => ShadowRoot | Node | Document
A root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.

Machine API

The splitter api exposes the following methods:

focused
boolean
Whether the splitter is focused.
dragging
boolean
Whether the splitter is being dragged.
bounds
PanelBounds | undefined
The bounds of the currently dragged splitter handle.
setToMinSize
(id: PanelId) => void
Function to set a panel to its minimum size.
setToMaxSize
(id: PanelId) => void
Function to set a panel to its maximum size.
setSize
(id: PanelId, size: number) => void
Function to set the size of a panel.

Data Attributes

Root

name
desc
data-scope
splitter
data-part
root
data-orientation
The orientation of the slider

Panel

name
desc
data-scope
splitter
data-part
panel
data-orientation
The orientation of the slider

Resize Trigger

name
desc
data-scope
splitter
data-part
resize-trigger
data-orientation
The orientation of the slider