

<Preview name="BasicResizableExample" />

## Overview [#overview]

The **Resizable** component provides a flexible system for creating resizable panel layouts. Built on [react-resizable-panels](https://github.com/bvaughn/react-resizable-panels), it supports horizontal and vertical orientations, customizable handles, and flexible sizing constraints.

## Usage [#usage]

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

```tsx
<ResizablePanelGroup orientation="horizontal">
  <ResizablePanel>One</ResizablePanel>
  <ResizableHandle />
  <ResizablePanel>Two</ResizablePanel>
</ResizablePanelGroup>
```

## 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 { ResizablePanelGroup, ResizablePanel, ResizableHandle } from "@tilt-legal/cubitt-components/primitives";

    export default function Component() {
      return (
        <ResizablePanelGroup
          orientation="vertical"
          className="min-h-[300px] 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>
      );
    }
    ```
  </Tab>
</Tabs>

### With Handle [#with-handle]

Add `withHandle` to display a visible drag handle on the resize bar.

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

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

    export default function Component() {
      return (
        <ResizablePanelGroup
          orientation="horizontal"
          className="min-h-[200px] max-w-md rounded-lg border"
        >
          <ResizablePanel defaultSize={50}>
            <div className="flex h-full items-center justify-center p-6">
              <span className="font-semibold">One</span>
            </div>
          </ResizablePanel>
          <ResizableHandle withHandle />
          <ResizablePanel defaultSize={50}>
            <div className="flex h-full items-center justify-center p-6">
              <span className="font-semibold">Two</span>
            </div>
          </ResizablePanel>
        </ResizablePanelGroup>
      );
    }
    ```
  </Tab>
</Tabs>

### Custom Handle [#custom-handle]

Pass a custom React element to `withHandle` for full control over the handle appearance.

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

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

    export default function Component() {
      return (
        <ResizablePanelGroup orientation="horizontal">
          <ResizablePanel
            defaultSize={30}
            className="h-[200px] rounded-lg border bg-background"
          >
            <div className="flex h-full items-center justify-center p-6">
              <span className="font-semibold">Sidebar</span>
            </div>
          </ResizablePanel>
          <ResizableHandle
            withHandle={<span className="h-8 w-1 rounded-full bg-border" />}
            className="!w-2 !bg-transparent"
          />
          <ResizablePanel
            defaultSize={70}
            className="h-[200px] rounded-lg border bg-background"
          >
            <div className="flex h-full items-center justify-center p-6">
              <span className="font-semibold">Content</span>
            </div>
          </ResizablePanel>
        </ResizablePanelGroup>
      );
    }
    ```
  </Tab>
</Tabs>

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

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

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

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

    export default function Component() {
      return (
        <ResizablePanelGroup
          orientation="horizontal"
          className="min-h-[200px] rounded-lg border"
        >
          <ResizablePanel defaultSize={280} minSize={200} maxSize={400}>
            <div className="flex h-full items-center justify-center p-6">
              <span className="font-semibold">Fixed Sidebar (280px)</span>
            </div>
          </ResizablePanel>
          <ResizableHandle withHandle />
          <ResizablePanel>
            <div className="flex h-full items-center justify-center p-6">
              <span className="font-semibold">Flexible Content</span>
            </div>
          </ResizablePanel>
        </ResizablePanelGroup>
      );
    }
    ```
  </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 orientation of the panel layout.        |
| `onLayoutChange` | `(layout: Layout) => void`   | —              | Callback when panel sizes change.           |
| `className`      | `string`                     | —              | Additional CSS classes for the panel group. |

### ResizablePanel [#resizablepanel]

Individual panel within the group.

Size props accept flexible units:

* **Numbers** are pixels (e.g., `defaultSize={420}` = 420px)
* **Strings without units** are percentages (e.g., `defaultSize="50"` = 50%)
* **Strings with units** use that unit (e.g., `"10rem"`, `"50vh"`)

| Prop            | Type               | Default | Description                                     |
| --------------- | ------------------ | ------- | ----------------------------------------------- |
| `defaultSize`   | `number \| string` | —       | Initial size (pixels, percentage, or CSS unit). |
| `minSize`       | `number \| string` | —       | Minimum size constraint.                        |
| `maxSize`       | `number \| string` | —       | Maximum size constraint.                        |
| `collapsible`   | `boolean`          | `false` | Whether the panel can be collapsed.             |
| `collapsedSize` | `number \| string` | —       | Size when collapsed.                            |
| `onResize`      | `(size) => void`   | —       | Callback when panel is resized.                 |
| `className`     | `string`           | —       | Additional CSS classes for the panel.           |

### ResizableHandle [#resizablehandle]

Draggable handle between panels.

| Prop         | Type                         | Default | Description                                                               |
| ------------ | ---------------------------- | ------- | ------------------------------------------------------------------------- |
| `withHandle` | `boolean \| React.ReactNode` | `false` | Show a visible grip handle. Pass `true` for default, or a custom element. |
| `disabled`   | `boolean`                    | `false` | Disable resizing via this handle.                                         |
| `className`  | `string`                     | —       | Additional CSS classes for the handle.                                    |

## Hooks [#hooks]

### useResizablePanelRef [#useresizablepanelref]

Get a ref to imperatively control a panel (collapse, expand, resize).

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

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

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

// Imperative methods:
panelRef.current?.collapse(); // Collapse the panel
panelRef.current?.expand(); // Expand the panel
panelRef.current?.isCollapsed(); // Check if collapsed
panelRef.current?.getSize(); // { asPercentage: number, inPixels: number }
```

### useResizableGroupRef [#useresizablegroupref]

Get a ref to imperatively control the entire group layout.

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

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

  const resetLayout = () => {
    groupRef.current?.setLayout({ left: 30, right: 70 });
  };

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

// Imperative methods:
groupRef.current?.getLayout();          // { [panelId]: percentage }
groupRef.current?.setLayout({ ... });   // Set new layout by panel IDs
```

### useResizableDefaultLayout [#useresizabledefaultlayout]

Persist and restore layouts to storage (localStorage, sessionStorage, or custom).

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

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

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

## Types [#types]

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

## Credits [#credits]

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