Skip to content

SplitPane

import { SplitPane } from '@delightstack/components';
Left Pane

Drag the divider to resize.

Right Pane

Content adjusts automatically.

View code
<SplitPane>
{#snippet first()}
<div>Left Pane</div>
{/snippet}
{#snippet second()}
<div>Right Pane</div>
{/snippet}
</SplitPane>

A horizontal split with constrained sidebar size and snap points.

Sidebar

Navigation items go here. Constrained between 15% and 40%.

Content

Main content area. Sidebar snaps at 25% and 33%.

View code
<script>
import { SplitPane } from '@delightstack/components';
let sidebarSize = $state(25);
</script>
<SplitPane
bind:size={sidebarSize}
min_size={15}
max_size={40}
snap={[25, 33]}
collapsible
>
{#snippet first()}
<nav>Sidebar</nav>
{/snippet}
{#snippet second()}
<main>Content</main>
{/snippet}
</SplitPane>

Stack panes top and bottom instead of left and right.

Editor

Top pane takes 70% of the height.

Terminal

$ pnpm run build

View code
<SplitPane vertical size={70}>
{#snippet first()}
<div>Editor</div>
{/snippet}
{#snippet second()}
<div>Terminal</div>
{/snippet}
</SplitPane>

Double-click the divider to collapse the smaller pane. An expand button appears on the collapsed edge.

First Pane

Double-click divider to collapse.

Second Pane

No pane collapsed

View code
<script>
import { SplitPane } from '@delightstack/components';
let collapsed = $state<'first' | 'second' | null>(null);
</script>
<SplitPane collapsible bind:collapsed>
{#snippet first()}
<div>First Pane</div>
{/snippet}
{#snippet second()}
<div>Second Pane</div>
{/snippet}
</SplitPane>

Combine multiple SplitPanes for complex layouts.

File Tree
src/
app.ts
index.ts
lib/
utils.ts
Editor
function hello() {
  return 'world';
}
Output

Build succeeded in 0.42s

View code
<SplitPane size={20} collapsible>
{#snippet first()}
<div>File Tree</div>
{/snippet}
{#snippet second()}
<SplitPane vertical size={70}>
{#snippet first()}
<div>Editor</div>
{/snippet}
{#snippet second()}
<div>Output</div>
{/snippet}
</SplitPane>
{/snippet}
</SplitPane>

The divider snaps to specified percentage positions during drag.

Pane A

Snaps at 25%, 50%, 75%. Current: 50%

Pane B

Drag slowly near snap points to feel the effect.

View code
<SplitPane snap={[25, 50, 75]} snap_threshold={5}>
{#snippet first()}
<div>Pane A</div>
{/snippet}
{#snippet second()}
<div>Pane B</div>
{/snippet}
</SplitPane>
PropTypeDefaultDescription
verticalbooleanfalseVertical split (top/bottom) instead of horizontal (left/right)
sizenumber50First pane size as a percentage (bindable)
min_sizenumber10Minimum first pane size (%)
max_sizenumber90Maximum first pane size (%)
snapnumber[][]Snap points as percentages
snap_thresholdnumber3Distance in % to trigger snap
collapsiblebooleanfalseAllow collapsing panes
collapsed'first' | 'second' | nullnullWhich pane is collapsed (bindable)
idstringautoElement ID
classstring''Additional CSS classes
firstSnippet-First pane content
secondSnippet-Second pane content
EventDetailDescription
onresize{ size: number }Fired when pane size changes
oncollapse{ pane: 'first' | 'second' | null }Fired when a pane is collapsed or expanded

The divider is focusable and supports the following keyboard controls:

KeyAction
Arrow Left / Arrow UpDecrease first pane size by 1%
Arrow Right / Arrow DownIncrease first pane size by 1%
Shift + ArrowAdjust by 5%
HomeSet to min_size
EndSet to max_size
EnterToggle collapse of the smaller pane (when collapsible)
  • Divider has role="separator" with aria-orientation matching the layout direction
  • aria-valuenow, aria-valuemin, and aria-valuemax reflect the current pane size
  • aria-label="Resize panes" on the divider
  • Collapsed panes have aria-hidden="true"
  • Expand buttons have descriptive aria-label attributes
  • Focus indicator visible on the divider via focus-visible
  • Touch support with touch-action: none on the divider
  • Respects prefers-reduced-motion for collapse transitions