Westy Design Systemv0.2.7
OverviewComponentsExamplesStorybook

Foundations

  • Typography
  • Colors
  • Spacing
  • Radius
  • Shadows
  • Icons

Components

  • Accordion
  • Alert
  • Alert Dialog
  • Aspect Ratio
  • Avatar
  • Badge
  • Breadcrumb
  • Button
  • Button Group
  • Calendar
  • Card
  • Carousel
  • Chart
  • Checkbox
  • Collapsible
  • Combobox
  • Command
  • Context Menu
  • Data Table
  • Date Picker
  • Dialog
  • Direction
  • Drawer
  • Dropdown Menu
  • Empty
  • Field
  • Hover Card
  • Input
  • Input Group
  • Input OTP
  • Item
  • Kbd
  • Label
  • Menubar
  • Native Select
  • Navigation Menu
  • Pagination
  • Popover
  • Progress
  • Questionnaire
  • Radio Group
  • Resizable
  • Scroll Area
  • Select
  • Separator
  • Sheet
  • Sidebar
  • Skeleton
  • Slider
  • Sonner
  • Spinner
  • Switch
  • Table
  • Tabs
  • Textarea
  • Toggle
  • Toggle Group
  • Tooltip

Chat

  • Attachment
  • Bubble
  • Marker
  • Message
  • Message Scroller

Components

Resizable

Accessible resizable panel groups and layouts with keyboard support.

Playground

One
Two
—orientation
—withHandle
—collapsible
—dir
Usage
Three parts wrapping react-resizable-panels: ResizablePanelGroup lays out the panels along its orientation, ResizablePanel wraps each region, and ResizableHandle draws the draggable divider with the border token. Groups nest — place a group inside a panel to split it along the other axis. Sizes are strings for percentages ("50%") and numbers for pixels.
One
Two
Three
import {
  ResizableHandle,
  ResizablePanel,
  ResizablePanelGroup,
} from "@workspace/ui/components/resizable"

<ResizablePanelGroup
  orientation="horizontal"
  className="max-w-md rounded-lg border"
>
  <ResizablePanel defaultSize="50%">
    <div className="flex h-[200px] items-center justify-center p-6">
      <span className="font-semibold">One</span>
    </div>
  </ResizablePanel>
  <ResizableHandle />
  <ResizablePanel defaultSize="50%">
    <ResizablePanelGroup orientation="vertical">
      <ResizablePanel defaultSize="25%">
        <div className="flex h-full items-center justify-center p-6">
          <span className="font-semibold">Two</span>
        </div>
      </ResizablePanel>
      <ResizableHandle />
      <ResizablePanel defaultSize="75%">
        <div className="flex h-full items-center justify-center p-6">
          <span className="font-semibold">Three</span>
        </div>
      </ResizablePanel>
    </ResizablePanelGroup>
  </ResizablePanel>
</ResizablePanelGroup>
Vertical
Set orientation="vertical" to stack panels top to bottom — the group switches to a column layout and the handle becomes a horizontal divider. Size the group with a min-height — the primitive sets its own inline height: 100%, so a height utility on className is overridden.
Header
Content
<ResizablePanelGroup
  orientation="vertical"
  className="min-h-[200px] max-w-md rounded-lg border"
>
  <ResizablePanel defaultSize="25%">
    <div className="flex h-full items-center justify-center p-6">
      <span className="font-semibold">Header</span>
    </div>
  </ResizablePanel>
  <ResizableHandle />
  <ResizablePanel defaultSize="75%">
    <div className="flex h-full items-center justify-center p-6">
      <span className="font-semibold">Content</span>
    </div>
  </ResizablePanel>
</ResizablePanelGroup>
With handle
By default the divider is a hairline. Add withHandle to render a small grip on top of it — a rounded pill in the border token that rotates with the orientation — making the affordance visible instead of discovered on hover.
Sidebar
Content
<ResizablePanelGroup
  orientation="horizontal"
  className="min-h-[200px] max-w-md rounded-lg border"
>
  <ResizablePanel defaultSize="25%">
    <div className="flex h-full items-center justify-center p-6">
      <span className="font-semibold">Sidebar</span>
    </div>
  </ResizablePanel>
  <ResizableHandle withHandle />
  <ResizablePanel defaultSize="75%">
    <div className="flex h-full items-center justify-center p-6">
      <span className="font-semibold">Content</span>
    </div>
  </ResizablePanel>
</ResizablePanelGroup>
Collapsible panel
A panel with collapsible snaps to its collapsedSize when dragged below minSize — the classic icon-rail sidebar. Mixing units works: percentage strings for the fluid sizes, a pixel number for the fixed collapsed rail.
Sidebar
Content
<ResizablePanelGroup
  orientation="horizontal"
  className="min-h-[200px] max-w-md rounded-lg border"
>
  <ResizablePanel
    defaultSize="30%"
    minSize="20%"
    collapsible
    collapsedSize={48}
  >
    <div className="flex h-full items-center justify-center overflow-hidden p-6">
      <span className="truncate font-semibold">Sidebar</span>
    </div>
  </ResizablePanel>
  <ResizableHandle withHandle />
  <ResizablePanel defaultSize="70%">
    <div className="flex h-full items-center justify-center p-6">
      <span className="font-semibold">Content</span>
    </div>
  </ResizablePanel>
</ResizablePanelGroup>
Accessibility
The handle implements the window-splitter pattern: a focusable role="separator" that reports the panel size through aria-valuenow. Tab reaches each handle and shows the ring token as its focus indicator; arrow keys resize the adjacent panels, Home and End jump to the minimum and maximum, and Enter toggles a collapsible panel. Double-clicking a handle resets the panels to their default sizes — opt out with disableDoubleClick.
// keyboard users resize with the handle focused —
// Tab to the separator, then Arrow keys, Home/End, Enter (collapse)
<ResizablePanelGroup orientation="horizontal">
  <ResizablePanel collapsible collapsedSize={48}>{/* … */}</ResizablePanel>
  <ResizableHandle withHandle />
  <ResizablePanel>{/* … */}</ResizablePanel>
</ResizablePanelGroup>
API Reference
Thin wrappers over react-resizable-panels v4 — Group, Panel and Separator — so every primitive prop passes through. Size props accept a percentage string ("25%") or a pixel number. The handle styles with logical properties, so RTL — via the dir attribute or an ancestor — mirrors the layout correctly.
PartPropDefault
ResizablePanelGrouporientation?: "horizontal" | "vertical""horizontal"
ResizablePanelGrouponLayoutChanged?: (layout, meta) => void—
ResizablePaneldefaultSize?: number | stringauto
ResizablePanelminSize? / maxSize?: number | string—
ResizablePanelcollapsible?: booleanfalse
ResizablePanelcollapsedSize?: number | string0
ResizablePanelonResize?: (size, id, prev) => void—
ResizableHandlewithHandle?: booleanfalse
ResizableHandledisabled?: booleanfalse
ResizableHandledisableDoubleClick?: booleanfalse

Tokens used

5 design tokens consumed by the Resizable component.

  • --border

    Border

    bg-border
  • --ring

    Ring

    focus-visible:ring-ring
  • --background

    Background

    ring-offset-background
  • --radius

    Radius

    rounded-lg
  • --spacing

    Spacing unit (4px)

    h-6w-1