Skip to content

Splitter

hc-splitter splits two panes with a movable handle — the shadcn Resizable equivalent. It follows the WAI-ARIA Window Splitter pattern: the handle is a focusable role="separator" whose aria-valuenow tracks the primary pane’s size. installSplitter wires the pointer drag, keyboard resize, and ARIA; the layout is plain flexbox driven by a single --hc-splitter-pos custom property.

Give the container a cross-axis size (a height for the default horizontal layout).

Primary pane
Secondary pane
import { installSplitter } from '@hypermedia-components/core';
installSplitter(); // idempotent; returns an uninstaller

The zero-config @hypermedia-components/core/behaviors entry installs it automatically.

data-orientation="vertical" stacks the panes with a horizontal handle.

Top
Bottom
AttributePurpose
data-orientationhorizontal (default, side-by-side) or vertical (stacked).
data-valueInitial primary-pane size, percent (default 50).
data-min / data-maxAllowed range, percent (default 10 / 90).
data-stepKeyboard step, percent (default 5).
data-collapsibleDouble-click / Enter on the handle toggles the primary pane collapsed ↔ last-open.
data-persistlocalStorage key — saves and restores the position (a persisted 0 restores collapsed).

Tab to the handle, then:

KeyAction
/ (horizontal) or / (vertical)Resize by one step
HomeMinimum size
EndMaximum size
EnterToggle collapse (when data-collapsible)

DOM focus is on the handle; aria-valuenow / aria-valuemin / aria-valuemax describe the primary pane’s size to assistive tech.

Each resize dispatches a bubbling hc:splitterchange on the container:

splitter.addEventListener('hc:splitterchange', (e) => {
const { value, collapsed, orientation } = e.detail; // value: primary-pane %
});

collapsed is true while the primary pane is folded away (see below).

Add data-collapsible so the handle can fold the primary pane away and bring it back. Double-click the handle, or focus it and press Enter, to toggle between collapsed (0%) and the last open size.

Primary pane — double-click the handle
Secondary pane

A collapsed splitter carries data-collapsed on the container — style the panes off it — and hc:splitterchange reports detail.collapsed. The handle’s aria-valuenow stays within [min, max]; the collapsed state rides on data-collapsed rather than an out-of-range value.

Add data-persist="<key>" to mirror the position into localStorage and restore it on the next visit. A persisted 0 restores the collapsed state. Storage failures (private mode, disabled) degrade silently to the data-value default.

<div class="hc-splitter" data-orientation="horizontal"
data-collapsible data-persist="editor:sidebar" style="block-size:10rem">
</div>

data-persist covers the common localStorage case; reach for Hyperscript when you need custom storage (a cookie, a server round-trip, a different key shape):

<div class="hc-splitter" data-orientation="horizontal"
_="on hc:splitterchange call myStore.set('split', event.detail.value)">
</div>

More patterns: Hyperscript → Reacting to component events.

  • The handle is role="separator" + tabindex="0" with aria-valuenow / aria-valuemin / aria-valuemax and aria-controls pointing at the primary pane (per the APG Window Splitter pattern).
  • The separator’s aria-orientation is set automatically (a side-by-side split uses a vertical separator line, and vice-versa).
  • Give the handle an accessible name with aria-label or aria-labelledby (the primary pane’s heading).
Token pathPurpose
splitter.handle-sizeHandle thickness (the hit area).
splitter.handle-bg / handle-hover-bgHandle background (hover / focus tints with data-color).
splitter.grip-color / grip-active-colorThe centred grip bar.
splitter.grip-length / grip-thicknessGrip dimensions.
Show the generated CSS variables
--hc-splitter-handle-size | -handle-bg | -handle-hover-bg
--hc-splitter-grip-color | -grip-active-color | -grip-length | -grip-thickness
--hc-splitter-pos (runtime: the primary pane's size, set by installSplitter)

Three-or-more panes, nested splitters, and pixel-based minimums are deferred.

  • Separator — a static, non-interactive divider.
  • Card — common content for the panes.