Skip to main content

Resizable

A layout primitive that enables users to resize adjacent panels via drag or keyboard interaction. It supports horizontal and vertical orientations, flexible panel constraints, and WAI-ARIA compliant separator behavior.

The component is composed of:

  • Resizable (root container)
  • Resizable.Panel
  • Resizable.Handle

Usage

Basic horizontal split

import { Resizable } from '@nofinite/nui';

export function Example() {
return (
<Resizable>
<Resizable.Panel defaultSize={50}>Left</Resizable.Panel>
<Resizable.Handle />
<Resizable.Panel defaultSize={50}>Right</Resizable.Panel>
</Resizable>
);
}

Vertical split

<Resizable direction="vertical">
<Resizable.Panel defaultSize={30}>Top</Resizable.Panel>
<Resizable.Handle />
<Resizable.Panel defaultSize={70}>Bottom</Resizable.Panel>
</Resizable>

With constraints

<Resizable>
<Resizable.Panel minSize={20} maxSize={80} defaultSize={40} />
<Resizable.Handle />
<Resizable.Panel />
</Resizable>

With grip icon

<Resizable.Handle withIcon />

Layout change callback

<Resizable onLayout={(sizes) => console.log(sizes)} />

Props

Resizable (Root)

PropTypeDefaultDescription
direction'horizontal' | 'vertical'horizontalLayout direction
onLayout(sizes: number[]) => voidCalled after resize completes
classNamestringAdditional class names

Extends HTMLDivElement attributes.


Resizable.Panel

PropTypeDefaultDescription
defaultSizenumberInitial flex grow percentage
minSizenumber0Minimum size percentage
maxSizenumber100Maximum size percentage
classNamestringAdditional class names

Resizable.Handle

PropTypeDefaultDescription
withIconbooleanfalseShows grip icon inside handle
classNamestring Additional class names

Variants

Direction

<Resizable direction="horizontal" />
<Resizable direction="vertical" />

Available variants

  • horizontal
  • vertical

Guidelines

  • Use horizontal for sidebars and split editors
  • Use vertical for stacked panes and dashboards
  • Prefer consistent orientation across a workspace

Handle visual variant

<Resizable.Handle />
<Resizable.Handle withIcon />

Available variants

  • default
  • withIcon

Guidelines

  • Use icon grip for discoverability
  • Use default for minimal UI
  • Prefer icon when drag affordance is unclear

States

  • Default
  • Hover (handle highlight)
  • Focus visible (keyboard)
  • Dragging
  • Constraint-limited resize
  • Keyboard resize
  • Orientation-dependent cursor

Keyboard Interaction

KeyBehavior
Arrow keysResize panels based on orientation
Shift + ArrowResize by 10% step
HomeMove toward minimum bound
EndMove toward maximum bound

Handles follow separator interaction pattern.


Accessibility

  • Uses role="separator" on handle
  • Orientation via aria-orientation
  • Dynamic aria-valuenow updates
  • Keyboard operable resizing
  • Focusable handle with visible focus ring
  • Pointer drag does not remove keyboard operability (manual focus restoration)

Design Tokens

TokenUsage
--nui-border-defaultHandle divider color
--nui-color-primaryActive/hover handle color
--nui-bg-subtleFocus background
--nui-bg-surfaceGrip background
--nui-fg-mutedGrip icon color

Best Practices

Do

  • Define min/max constraints for predictable layouts
  • Use icon grips in complex editors
  • Persist layout using onLayout
  • Ensure panels contain overflow-safe content
  • Use consistent panel sizing strategy

Don’t

  • Nest many resizable groups without performance consideration
  • Omit constraints in critical layouts
  • Place scroll containers directly on handles
  • Use vertical + horizontal nesting without UX clarity