# 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.