Skip to content

Resizable panels

Lab Available in release assets

Resize two authored regions with bounded pointer and keyboard mechanics while preserving their native reading order and stacked fallback.

Resizable panels primary example

Show code
<section data-enhance="resizable-panels" aria-label="Editor panels">
  <section id="source-panel" data-panel>
    <h2>Source</h2>
    <p>Authored first in reading order and fully usable without JavaScript.</p>
  </section>
  <div role="separator" tabindex="0" aria-label="Resize source and preview" aria-controls="source-panel preview-panel" aria-orientation="vertical" aria-valuemin="20" aria-valuemax="80" aria-valuenow="50" aria-valuetext="50% for primary panel">
  </div>
  <section id="preview-panel" data-panel>
    <h2>Preview</h2>
    <p>Authored second in reading order.</p>
  </section>
</section>

Each authored example uses the production assets and includes copyable markup.

Anatomy

  • Labelled group
  • Two authored regions
  • Focusable ARIA separator
  • Minimum/current/maximum values

Variants and sizes

  • Inline split — shown above
  • Block split — shown above
  • RTL — shown above

Rendered fixtures exercise authored content and constrained layouts with the same production assets.

  • Default — shown above
  • Minimum — shown above
  • Maximum — shown above
  • Pointer dragging — shown above
  • Keyboard resizing — shown above
  • RTL — shown above
  • Narrow stacked fallback — shown above
  • Disconnected — shown above
  • Reconnected — shown above
  • Morphed separator — shown above
  • Long content — shown above

Interaction and keyboard behavior

Arrow keys change the logical primary size by 2%; Shift uses 10%; Home and End select authored bounds. Pointer capture is limited to the separator and released on up, cancel, or disconnect. refresh() reacquires authored elements after a morph. Persistence is explicitly outside core.

Accessibility

Use role=separator with tabindex, aria-controls, orientation, value min/max/now, and a human-readable value text. Regions remain in DOM reading order. Keep Lab until browser, screen-reader, zoom, pointer, touch, and RTL evidence supports promotion.

Contract
SPLITTER · APG pattern
Basis
APG Window Splitter as an explicitly experimental mapping; APG review/example work is incomplete
Behavior guarantees
  • An experimental Window Splitter: one named separator controls exactly two contained panels, or the behavior fails closed and the stacked reading order stays authoritative.
  • Normalizes orientation and bounded values, ignores disabled separators, and releases pointer capture on cancellation or disconnect.
  • Rebinds a replaced separator on refresh().
Evidence
  • tests/unit/library/resizable-panels.test.ts
  • tests/unit/library/advanced-component-contracts.test.ts

API

Add data-enhance=resizable-panels to the authored group and role=separator between exactly two regions. Optional --thin-panel-size starts at aria-valuenow. Call refresh() after server morphs; disconnect() before removal. Do not persist sizing in core.

Behavior tier: dependency-free

Custom properties

PropertyDefaultDescription
--thin-panel-size50%Initial logical size of the primary panel before interaction.

Fallback

Without JavaScript the two authored regions stack in normal reading order and the separator is visually inert.

Assets and dependencies

  • /labs.css
  • /labs.js

Dependencies: None

Source: packages/ui/src/items/resizable-panels/style.ts