# Resizable Panels separated by handles you drag or move with the arrow keys. ```ehtml Example import { ResizablePanelGroup, ResizablePanel, ResizableHandle, ResizableGrid, ResizableCell, ResizableGridline, } from "@elements/ui/resizable"; Folders Messages ... ... Header Inspector Files Editor ``` ## Parts | Part | What it is | |---|---| | `ResizablePanelGroup` | The flex row or column. Owns the layout: each panel's percent of the free space. | | `ResizablePanel` | A region with a size, limits and optional collapse. | | `ResizableHandle` | The separator between two panels: drag it or focus it and use the keys. | | `.resizable-grip` | The visible grip withHandle renders. | | `ResizableGrid` | A CSS grid whose columns and rows both resize. Owns a layout per axis. | | `ResizableCell` | Occupies one or more columns and rows. | | `ResizableGridline` | Resizes the columns or rows on either side of one boundary. Where a column and a row gridline cross, a drag resizes both. | ## Attributes ### ResizablePanelGroup | Attribute | Type | Default | Description | |---|---|---|---| | `orientation` | `"horizontal" \| "vertical"` | `"horizontal"` | Panels side by side, or stacked. | | `layout` | `number[]` (two-way) | `[]` | Every panel's percent, summing to 100. Bind it to read the layout or set it; empty uses the panels' defaults. | | `disabled` | `boolean` | `false` | No handle resizes. | | `disableCursor` | `boolean` | `false` | Leave the page cursor alone while dragging. | | `keyboardStep` | `number` | `10` | Percent an arrow key moves a handle. | | `autoSaveId` | `string` | `""` | Remembers the layout in localStorage under this id. | | `dir` | `"ltr" \| "rtl" \| ""` | `""` | Reading direction; empty inherits. | | `onLayoutChange` | `(layout: number[]) => void` | `() => {}` | Every change, including each pointer move. | | `onLayoutChanged` | `(layout: number[], meta: { isUserInteraction: boolean; requestedLayout: number[] }) => void` | `() => {}` | Once a drag ends, a key moves a handle, or code sets the layout. requestedLayout is the layout before constraints; save that one. | | `resizePreviewMode` | `"panel" \| "separator"` | `"panel"` | separator: a drag moves only the separator, and the panels resize on release. | ### ResizablePanel | Attribute | Type | Default | Description | |---|---|---|---| | `id` | `string` | `generated` | Keys the saved layout and the handle's aria-controls. | | `defaultSize` | `number \| string` | `even share` | Starting size. A number is px; a string takes px, %, rem, em, vh, vw; a bare string is percent. | | `minSize` | `number \| string` | `"0%"` | Smallest size. | | `maxSize` | `number \| string` | `"100%"` | Largest size. | | `collapsible` | `boolean` | `false` | Pushed past its threshold below minSize, it collapses to collapsedSize. | | `collapsedSize` | `number \| string` | `"0%"` | Size while collapsed. | | `collapsedThreshold` | `number \| string` | `half of min minus collapsed` | How far past minSize it must go to collapse, and be pulled to expand. | | `collapsed` | `boolean` (two-way) | `false` | Whether it is collapsed. Set it to collapse or expand; the group writes it back as the user drags. | | `disabled` | `boolean` | `false` | Neither resized nor pushed by its neighbors. | | `groupResizeBehavior` | `"preserve-relative-size" \| "preserve-pixel-size"` | `"preserve-relative-size"` | When the group resizes, keep this panel's percent or its px. | | `onResize` | `(size: PanelSize, id: string, prevSize: PanelSize \| undefined) => void` | `() => {}` | Its size changed, as { asPercentage, inPixels }; prevSize is undefined on the first layout. | | `onCollapse / onExpand` | `() => void` | `() => {}` | It collapsed or expanded. | ### ResizableHandle | Attribute | Type | Default | Description | |---|---|---|---| | `withHandle` | `boolean` | `false` | Shows a grip on the hairline. | | `disabled` | `boolean` | `false` | This handle does not resize. | | `fixed` | `boolean` | `false` | APG fixed size splitter: no arrow keys or dragging; Enter or a click toggles the panel before it between its size and collapsed. | | `disableDoubleClick` | `boolean` | `false` | A double click no longer resets the panel before it to its default size. | | `label` | `string` | `"Resize"` | The separator's accessible name. Pass "" with attrs aria-labelledby to name it by the pane's visible label. | | `preview` | `"panel" \| "separator" \| ""` | `""` | Overrides the group's resizePreviewMode for this handle. | | `onDragging` | `(dragging: boolean) => void` | `() => {}` | A pointer drag started or ended. | ### ResizableGrid | Attribute | Type | Default | Description | |---|---|---|---| | `columns, rows` | `number \| TrackSpec[]` | `2, 1` | A track count, or one { id, defaultSize, minSize, maxSize, collapsible, collapsedSize, collapsedThreshold, disabled } per track, in the panel units. | | `layout` | `{ columns: number[]; rows: number[] }` (two-way) | `{ columns: [], rows: [] }` | Every track's percent per axis. Its initial value is the default layout; bind it to read or set. | | `disabled, disableCursor, keyboardStep, autoSaveId, dir` | `as on the group` | `false, false, 10, "", ""` | As on ResizablePanelGroup; disableCursor also drops the gridlines' resize cursors. | | `onLayoutChange / onLayoutChanged` | `(layout, meta?) => void` | `() => {}` | Every change, and once a drag ends, a key moves a gridline or code sets the layout. | ### ResizableCell | Attribute | Type | Default | Description | |---|---|---|---| | `column, row` | `number` | `0` | The first column and row it occupies, from 0. | | `columnSpan, rowSpan` | `number` | `1` | How many tracks it spans. | ### ResizableGridline | Attribute | Type | Default | Description | |---|---|---|---| | `type` | `"column" \| "row"` | `"column"` | A column gridline is vertical and resizes columns; a row gridline resizes rows. | | `column, row` | `number` | `0` | The boundary it sits on (the leading edge of that track) and the first track of the other axis it runs beside. | | `rowSpan / columnSpan` | `number` | `0 (all)` | How many tracks it runs beside. Never beside a cell that spans its boundary. | | `withHandle, disabled, disableDoubleClick, label, onDragging` | `as on the handle` | `as on the handle` | As on ResizableHandle. | ### all | Attribute | Type | Default | Description | |---|---|---|---| | `class, attrs` | `string, Record` | `"", {}` | Extra classes and attributes on the element. | ## Slots | Slot | Part | Content | |---|---|---| | `default` | `ResizablePanelGroup` | Panels and handles, alternating. | | `default` | `ResizablePanel` | The panel's content; may hold another group. | ## Keyboard | Keys | Action | |---|---| | `ArrowLeft / ArrowRight` | Horizontal group: moves the focused handle by keyboardStep. | | `ArrowUp / ArrowDown` | Vertical group: moves the focused handle by keyboardStep. | | `Home` | The panel before the handle to its smallest size, collapsed if it can. | | `End` | The panel before the handle to its largest size. | | `Enter` | Collapses the panel before the handle, or restores it. | | `Arrows, Home, End, Enter (gridline)` | A column gridline takes Left and Right, a row gridline Up and Down; Home, End and Enter act on the track before it. | | `F6 / Shift + F6` | Moves focus through the window panes: from a handle to the pane after it (Shift: before it), from a pane to the next or previous pane. | ## Data attributes | Attribute | Values | On | Description | |---|---|---|---| | `data-orientation` | `"horizontal" \| "vertical"` | root | | | `data-group, data-panel-group` | present | root | | | `data-panel-size` | percent | .resizable-panel | | | `data-collapsible` | present | .resizable-panel | | | `data-collapsed` | present | .resizable-panel | While collapsed. | | `data-state` | `"inactive" \| "hover" \| "drag"` | .resizable-handle | | | `data-preview` | present | .resizable-handle | While a separator preview is shown (resizePreviewMode separator). | | `data-dragging` | present | .resizable-handle | While dragged. | | `data-disabled` | present | root, .resizable-panel, .resizable-handle | | | `data-fixed` | present | .resizable-handle | A fixed size splitter. | | `data-edge-hover, data-edge-dragging` | present | root | The pointer is on, or dragging, an edge where two panels meet without a separator. | | `data-grid` | present | .resizable-grid | | | `data-cursor` | `"move" \| "col-resize" \| "row-resize"` | .resizable-grid | The pointer is on a resize target; move where two axes meet. | | `data-dragging` | present | .resizable-grid | While a pointer drag runs. | | `data-cell, data-column, data-row, data-column-span, data-row-span` | present, index | .resizable-cell | | | `data-type` | `"column" \| "row"` | .resizable-gridline | | | `data-state` | `"inactive" \| "hover" \| "drag"` | .resizable-gridline | | ## Accessibility - Each handle is a focusable separator (WAI-ARIA window splitter) with aria-orientation, aria-controls naming the panel before it, and aria-valuenow, aria-valuemin and aria-valuemax in percent. - Arrow keys move it, Home and End go to the limits, Enter collapses and restores, F6 moves between the window panes. A fixed handle takes only Enter. Separators are optional: without one, the edge between two panels is the drag target. - The focus ring is a box-shadow on the hairline; the hit area is wider than the line, wider still on touch screens. - A grid's gridlines are separators too, with aria-controls naming the cells on their leading side. F6 moves through the cells. ## See also - [Sidebar](sidebar): An app sidebar that collapses to icons or off the canvas and becomes a sheet on phones. - [Carousel](carousel): Slides you swipe, drag or step through, with momentum, snapping, loop and autoplay. - [ScrollArea](scroll-area): A scroll container with thin, themed scrollbars over native scrolling.