User-sized panes for split views: inbox + message, media grid + details, editor + preview. Keyboard resizing, pixel or percent limits, collapsible panes, nested groups and a remembered layout.
- Northwind — master services agreement.pdf412 KB · Nov 4
- Kadıköy Bistro — renewal 2027.pdf286 KB · Oct 29
- Lumen Architects — NDA.pdf118 KB · Oct 12
Installation
The whole kit as one package — get updates by bumping the version. Add the styles to globals.css: @import "@vamos-ui/react/styles.css";
Usage
import { ResizableGroup, ResizablePanel, ResizableHandle } from "@vamos-ui/react";
<ResizableGroup autoSaveId="inbox" className="h-[560px]">
<ResizablePanel id="list" defaultSize="35%" minSize="25%">…</ResizablePanel>
<ResizableHandle withGrip />
<ResizablePanel id="detail">…</ResizablePanel>
</ResizableGroup>Keyboard (WAI-ARIA Window Splitter): focus the handle, then ← → (or ↑ ↓), Home / End; Enter collapses a collapsible pane.
Glass mode: surfaces inside the group stop blurring while a handle is dragged, to avoid flicker.
On phones, show one pane and open the other in a Sheet — this is not automatic.
Examples
Split view with saved layout (CRM inbox)
autoSaveId stores the layout in localStorage (safe when storage is blocked). Panels need stable ids. Pixel limits keep the list readable on any width.
- Laura Callahan09:42
Renewal — revised quote
Thanks, the 3-year option works for us if…
- Jonas Weber08:15
Onboarding call
Could we move it to Thursday at 14:00?
- Priya NairMon
Invoice INV-2026-0411
Payment was sent yesterday, reference…
- Kenji SatoSun
API rate limits
We're hitting 429s on the contacts endpoint…
Renewal — revised quote
Laura Callahan · Northwind Traders
Thanks, the 3-year option works for us if the onboarding hours can be included. Our board meets on December 3; I'd like to bring a signed draft.
Nested groups (CMS editor)
A vertical group inside a horizontal one. Double-click a handle to reset its panes.
<section class="hero">
<h1>{{ page.title }}</h1>
<p>{{ page.lead }}</p>
</section>Compiled in 42 ms · 0 warnings
Autumn menu is here
Twelve new dishes from the Aegean coast, served from November 14.
Collapsible pane (HR directory)
collapsible + collapsedSize; drive it with useResizablePanelRef() → collapse() / expand().
- Elif Kaya — Engineering manager
- Mert Aydın — SRE
- Sofia Rossi — Designer
- Omar Haddad — Recruiter
- Emma Clarke — Payroll
Elif Kaya
Engineering manager · Istanbul office · 6 direct reports
API
ResizableGroup
| Prop | Type | Default |
|---|---|---|
orientationPanes side by side or stacked. direction is an alias. | "horizontal" | "vertical" | "horizontal" |
autoSaveIdPersist the layout under this key. | string | — |
storageStorage for autoSaveId (e.g. a cookie adapter so the server renders the saved layout). | { getItem; setItem } | safe localStorage |
defaultLayoutInitial layout in percentages. | Record<panelId, number> | — |
onLayoutChangedAfter a resize ends (pointer released / key pressed). | (layout, meta) => void | — |
onLayoutChangeOn every pointer move while resizing. | (layout) => void | — |
groupRefgetLayout() / setLayout(). See useResizableGroupRef(). | Ref<ResizableGroupHandle> | — |
disabledTurn resizing off. | boolean | false |
ResizablePanel
| Prop | Type | Default |
|---|---|---|
idStable id (required for saved layouts). | string | — |
defaultSizeNumber = px; "35" or "35%" = percent; also rem, em, vh, vw. | number | string | — |
minSize · maxSizeLimits, same units as defaultSize. | number | string | "0%" · "100%" |
collapsibleCollapses when dragged below minSize. | boolean | false |
collapsedSizeSize when collapsed. | number | string | "0%" |
onResizeCalled when the size changes. | (size: { asPercentage; inPixels }) => void | — |
panelRefcollapse(), expand(), resize(), getSize(), isCollapsed(). See useResizablePanelRef(). | Ref<ResizablePanelHandle> | — |
ResizableHandle
| Prop | Type | Default |
|---|---|---|
withGripA visible grip in the middle of the line. | boolean | false |
aria-labelName of the splitter, e.g. "Resize thread list". | string | — |
disabledThis handle can't be dragged. | boolean | false |
disableDoubleClickTurn off double-click to reset. | boolean | false |