Resizable
A split view whose panels you drag, with a layout it remembers.
Walkthrough
1. Basic
A sidebar and its content. Drag the handle, or focus it and use the arrow keys; autoSaveId remembers the layout in localStorage, so a pane someone dragged is still there tomorrow.
Sidebar
Drag the handle
<script lang="ts"> import { ResizablePanelGroup, ResizablePanel, ResizableHandle, Text } from 'omaris';</script><div class="h-64 w-full overflow-hidden rounded-shape-lg border border-border"> <ResizablePanelGroup autoSaveId="docs-resizable-basic"> <ResizablePanel defaultSize={30} min={18}> <div class="flex h-full items-center justify-center bg-surface-container-low"> <Text variant="body-sm" tone="muted">Sidebar</Text> </div> </ResizablePanel> <ResizableHandle withHandle label="Resize sidebar" /> <ResizablePanel> <div class="flex h-full items-center justify-center"> <Text variant="body-sm" tone="muted">Drag the handle</Text> </div> </ResizablePanel> </ResizablePanelGroup></div> 2. Snapping and pixel limits
snapPoints pull the handle onto a share as it comes near — the line pulses as it lands — and min="200px" is a floor in pixels that holds however the group is resized. The readout is onLayout.
0%
snaps at 25 · 50 · 75, never under 200px0%
takes whatever is left<script lang="ts"> import { ResizablePanelGroup, ResizablePanel, ResizableHandle, Text } from 'omaris'; let sizes = $state<number[]>([]);</script><div class="flex w-full flex-col gap-3"> <div class="h-56 w-full overflow-hidden rounded-shape-lg border border-border"> <ResizablePanelGroup bind:sizes> <ResizablePanel defaultSize={40} min="200px" snapPoints={[25, 50, 75]}> <div class="flex h-full flex-col items-center justify-center gap-1 bg-surface-container-low" > <Text variant="title-md" tabular>{Math.round(sizes[0] ?? 0)}%</Text> <Text variant="label-sm" tone="muted">snaps at 25 · 50 · 75, never under 200px</Text> </div> </ResizablePanel> <ResizableHandle withHandle /> <ResizablePanel min={15}> <div class="flex h-full flex-col items-center justify-center gap-1"> <Text variant="title-md" tabular>{Math.round(sizes[1] ?? 0)}%</Text> <Text variant="label-sm" tone="muted">takes whatever is left</Text> </div> </ResizablePanel> </ResizablePanelGroup> </div> <Text variant="body-sm" tone="muted" tabular> {sizes.map((size) => `${size.toFixed(1)}%`).join(' · ')} </Text></div> 4. Nested
Groups nest, so a three-pane inbox is two groups and nothing else.
Folders
Message list
Preview
<script lang="ts"> import { ResizablePanelGroup, ResizablePanel, ResizableHandle, Text } from 'omaris';</script><div class="h-72 w-full overflow-hidden rounded-shape-lg border border-border"> <ResizablePanelGroup> <ResizablePanel defaultSize={28} min={20}> <div class="flex h-full items-center justify-center bg-surface-container-low"> <Text variant="body-sm" tone="muted">Folders</Text> </div> </ResizablePanel> <ResizableHandle withHandle /> <ResizablePanel> <ResizablePanelGroup direction="vertical"> <ResizablePanel defaultSize={45}> <div class="flex h-full items-center justify-center"> <Text variant="body-sm" tone="muted">Message list</Text> </div> </ResizablePanel> <ResizableHandle withHandle /> <ResizablePanel> <div class="flex h-full items-center justify-center bg-surface-container-low"> <Text variant="body-sm" tone="muted">Preview</Text> </div> </ResizablePanel> </ResizablePanelGroup> </ResizablePanel> </ResizablePanelGroup></div> 5. Vertical and persisted
direction="vertical" stacks the panels; the handle turns with them and the up and down arrows drive it. autoSaveId keeps this split across reloads, and onLayout reports every settled layout.
Editor
Terminal
onLayout → …
<script lang="ts"> import { ResizablePanelGroup, ResizablePanel, ResizableHandle, Text } from 'omaris'; let sizes = $state<number[]>([]);</script><div class="flex w-full flex-col gap-3"> <div class="h-72 w-full overflow-hidden rounded-shape-lg border border-border"> <ResizablePanelGroup direction="vertical" autoSaveId="docs-resizable-vertical" onLayout={(next) => (sizes = next)} > <ResizablePanel defaultSize={60} min={20}> <div class="flex h-full items-center justify-center"> <Text variant="body-sm" tone="muted">Editor</Text> </div> </ResizablePanel> <ResizableHandle withHandle label="Resize terminal" /> <ResizablePanel min={15} collapsible collapsedSize={0}> <div class="flex h-full items-center justify-center bg-surface-container-low"> <Text variant="body-sm" tone="muted">Terminal</Text> </div> </ResizablePanel> </ResizablePanelGroup> </div> <Text variant="body-sm" tone="muted" tabular> onLayout → {sizes.map((size) => `${size.toFixed(1)}%`).join(' / ') || '…'} </Text></div> 6. Overridden
Every part is reachable. hitArea={16} widens the pointer target without touching the line, classes restyles the line and the grip, and a disabled group keeps its layout but nothing in it moves.
Wide hit area
Restyled line and grip
Disabled group
Nothing here moves
<script lang="ts"> import { ResizablePanelGroup, ResizablePanel, ResizableHandle, Text } from 'omaris';</script><div class="flex w-full flex-col gap-4"> <div class="h-48 w-full overflow-hidden rounded-shape-lg border border-border"> <ResizablePanelGroup> <ResizablePanel defaultSize={35} min={20}> <div class="flex h-full items-center justify-center bg-surface-container-low"> <Text variant="body-sm" tone="muted">Wide hit area</Text> </div> </ResizablePanel> <ResizableHandle withHandle hitArea={16} classes={{ root: 'bg-surface-container after:bg-tertiary/40 hover:after:bg-tertiary data-dragging:after:bg-tertiary', grip: 'h-12 w-2 bg-tertiary/60 group-hover/handle:bg-tertiary group-data-dragging/handle:bg-tertiary' }} /> <ResizablePanel> <div class="flex h-full items-center justify-center"> <Text variant="body-sm" tone="muted">Restyled line and grip</Text> </div> </ResizablePanel> </ResizablePanelGroup> </div> <div class="h-32 w-full overflow-hidden rounded-shape-lg border border-border"> <ResizablePanelGroup disabled sizes={[40, 60]}> <ResizablePanel> <div class="flex h-full items-center justify-center bg-surface-container-low"> <Text variant="body-sm" tone="muted">Disabled group</Text> </div> </ResizablePanel> <ResizableHandle withHandle /> <ResizablePanel> <div class="flex h-full items-center justify-center"> <Text variant="body-sm" tone="muted">Nothing here moves</Text> </div> </ResizablePanel> </ResizablePanelGroup> </div></div>