

<Preview name="BasicResizableExample" />

## Overview [#overview]

Resizable creates panel layouts with draggable separators. It does not own a panel background, border, radius, or shadow; wrap it in `Card`, `Surface`, or an app-owned container when you need a framed area. The examples below use consumer-painted frame classes with `SurfaceProvider` so the resize handle reads the matching surface context.

## Usage [#usage]

```tsx
import {
  ResizableHandle,
  ResizablePanel,
  ResizablePanelGroup,
} from "@tilt-legal/cubitt-components/resizable";
import { SurfaceProvider } from "@tilt-legal/cubitt-components/utilities";
```

```tsx
<SurfaceProvider level={3}>
  <ResizablePanelGroup
    className="h-full min-h-80 w-full overflow-hidden rounded-xl border border-border-3 bg-surface-3"
    orientation="horizontal"
  >
    <ResizablePanel>One</ResizablePanel>
    <ResizableHandle />
    <ResizablePanel>Two</ResizablePanel>
  </ResizablePanelGroup>
</SurfaceProvider>
```

## Examples [#examples]

### Vertical [#vertical]

Use `orientation="vertical"` to stack panels vertically.

<Tabs items="[&#x22;Preview&#x22;, &#x22;Code&#x22;]">
  <Tab value="Preview">
    <Preview name="VerticalResizableExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import {
      ResizableHandle,
      ResizablePanel,
      ResizablePanelGroup,
    } from "@tilt-legal/cubitt-components/resizable";
    import { SurfaceProvider } from "@tilt-legal/cubitt-components/utilities";

    export default function Component() {
      return (
        <SurfaceProvider level={3}>
          <ResizablePanelGroup
            className="h-full min-h-80 w-full overflow-hidden rounded-xl border border-border-3 bg-surface-3"
            orientation="vertical"
          >
            <ResizablePanel defaultSize={25}>
              <div className="flex h-full items-center justify-center p-6">
                <span className="font-medium">Header</span>
              </div>
            </ResizablePanel>
            <ResizableHandle />
            <ResizablePanel defaultSize={75}>
              <div className="flex h-full items-center justify-center p-6">
                <span className="font-medium">Content</span>
              </div>
            </ResizablePanel>
          </ResizablePanelGroup>
        </SurfaceProvider>
      );
    }
    ```
  </Tab>
</Tabs>

### With Handle [#with-handle]

Add `withHandle` to display a visible grip on the resize separator.

<Tabs items="[&#x22;Preview&#x22;, &#x22;Code&#x22;]">
  <Tab value="Preview">
    <Preview name="ResizableWithHandleExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import {
      ResizableHandle,
      ResizablePanel,
      ResizablePanelGroup,
    } from "@tilt-legal/cubitt-components/resizable";
    import { SurfaceProvider } from "@tilt-legal/cubitt-components/utilities";

    export default function Component() {
      return (
        <SurfaceProvider level={3}>
          <ResizablePanelGroup
            className="h-full min-h-80 w-full overflow-hidden rounded-xl border border-border-3 bg-surface-3"
            orientation="horizontal"
          >
            <ResizablePanel defaultSize={50}>
              <div className="flex h-full items-center justify-center p-6">
                <span className="font-medium">One</span>
              </div>
            </ResizablePanel>
            <ResizableHandle withHandle />
            <ResizablePanel defaultSize={50}>
              <div className="flex h-full items-center justify-center p-6">
                <span className="font-medium">Two</span>
              </div>
            </ResizablePanel>
          </ResizablePanelGroup>
        </SurfaceProvider>
      );
    }
    ```
  </Tab>
</Tabs>

### Pixel-Based Sizing [#pixel-based-sizing]

Use numeric values for pixel-based constraints. The second panel fills the remaining space.

<Tabs items="[&#x22;Preview&#x22;, &#x22;Code&#x22;]">
  <Tab value="Preview">
    <Preview name="PixelSizeResizableExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    import {
      ResizableHandle,
      ResizablePanel,
      ResizablePanelGroup,
    } from "@tilt-legal/cubitt-components/resizable";
    import { SurfaceProvider } from "@tilt-legal/cubitt-components/utilities";

    export default function Component() {
      return (
        <SurfaceProvider level={3}>
          <ResizablePanelGroup
            className="h-full min-h-80 w-full overflow-hidden rounded-xl border border-border-3 bg-surface-3"
            orientation="horizontal"
          >
            <ResizablePanel defaultSize={280} maxSize={400} minSize={200}>
              <div className="flex h-full items-center justify-center p-6">
                <span className="font-medium">Fixed Sidebar (280px)</span>
              </div>
            </ResizablePanel>
            <ResizableHandle withHandle />
            <ResizablePanel>
              <div className="flex h-full items-center justify-center p-6">
                <span className="font-medium">Flexible Content</span>
              </div>
            </ResizablePanel>
          </ResizablePanelGroup>
        </SurfaceProvider>
      );
    }
    ```
  </Tab>
</Tabs>

## API Reference [#api-reference]

### ResizablePanelGroup [#resizablepanelgroup]

Container component that manages the resizable panel layout.

| Prop             | Type                         | Default        | Description                                                 |
| ---------------- | ---------------------------- | -------------- | ----------------------------------------------------------- |
| `orientation`    | `"horizontal" \| "vertical"` | `"horizontal"` | The panel layout direction.                                 |
| `onLayoutChange` | `(layout: Layout) => void`   | -              | Callback when panel sizes change.                           |
| `className`      | `string`                     | -              | Additional classes for layout sizing and app-owned framing. |

### ResizablePanel [#resizablepanel]

Panel size props accept percentages, pixels, relative font units, and viewport units. Numeric values are treated as pixels, while strings without units are treated as percentages.

| Prop            | Type               | Default | Description                                  |
| --------------- | ------------------ | ------- | -------------------------------------------- |
| `defaultSize`   | `number \| string` | -       | Initial size.                                |
| `minSize`       | `number \| string` | -       | Minimum size constraint.                     |
| `maxSize`       | `number \| string` | -       | Maximum size constraint.                     |
| `collapsible`   | `boolean`          | `false` | Whether the panel can collapse.              |
| `collapsedSize` | `number \| string` | -       | Size when collapsed.                         |
| `onResize`      | `(size) => void`   | -       | Callback when the panel is resized.          |
| `className`     | `string`           | -       | Additional classes for panel content layout. |

### ResizableHandle [#resizablehandle]

Draggable separator between panels.

| Prop         | Type                         | Default | Description                                                           |
| ------------ | ---------------------------- | ------- | --------------------------------------------------------------------- |
| `withHandle` | `boolean \| React.ReactNode` | `false` | Shows the default grip when `true`, or renders a custom grip element. |
| `disabled`   | `boolean`                    | `false` | Disables resizing through this handle.                                |
| `className`  | `string`                     | -       | Additional classes for the separator.                                 |

## Hooks [#hooks]

### useResizablePanelRef [#useresizablepanelref]

Get a ref to imperatively control a panel.

```tsx
import { useResizablePanelRef } from "@tilt-legal/cubitt-components/resizable";

function Component() {
  const panelRef = useResizablePanelRef();

  return (
    <ResizablePanelGroup orientation="horizontal">
      <ResizablePanel collapsible panelRef={panelRef}>
        Sidebar
      </ResizablePanel>
      <ResizableHandle />
      <ResizablePanel>Content</ResizablePanel>
    </ResizablePanelGroup>
  );
}
```

### useResizableGroupRef [#useresizablegroupref]

Get a ref to imperatively control the entire group layout.

```tsx
import { useResizableGroupRef } from "@tilt-legal/cubitt-components/resizable";

function Component() {
  const groupRef = useResizableGroupRef();

  return (
    <ResizablePanelGroup groupRef={groupRef} orientation="horizontal">
      <ResizablePanel id="left">Left</ResizablePanel>
      <ResizableHandle />
      <ResizablePanel id="right">Right</ResizablePanel>
    </ResizablePanelGroup>
  );
}
```

### useResizableDefaultLayout [#useresizabledefaultlayout]

Persist and restore layouts to storage.

```tsx
import { useResizableDefaultLayout } from "@tilt-legal/cubitt-components/resizable";

function Component() {
  const { defaultLayout } = useResizableDefaultLayout({
    panelIds: ["sidebar", "content"],
    storage: localStorage,
  });

  return (
    <ResizablePanelGroup defaultLayout={defaultLayout} orientation="horizontal">
      <ResizablePanel defaultSize={280} id="sidebar">
        Sidebar
      </ResizablePanel>
      <ResizableHandle />
      <ResizablePanel id="content">Content</ResizablePanel>
    </ResizablePanelGroup>
  );
}
```

## Types [#types]

```tsx
import type {
  ResizableLayout,
  ResizablePanelGroupHandle,
  ResizablePanelHandle,
  ResizablePanelSize,
} from "@tilt-legal/cubitt-components/resizable";
```

## Credits [#credits]

Built with [react-resizable-panels](https://github.com/bvaughn/react-resizable-panels).
