# PanelSplitter

> The draggable seam between two side-by-side panels; every split view in Max uses it, so one gesture works everywhere.

## Facts

- **Product**: Max
- **Family**: Layout
- **Global**: `window.DigitalCrew.PanelSplitter`
- **Source**: `max-agent: src/components/ui/panel-splitter.tsx`
- **Import in the app**: `import { PanelSplitter } from "@/components/ui/panel-splitter";`
- **Live preview**: /design/components/panel-splitter/preview.html
- **Page**: /design/components/panel-splitter

## Guidelines

**Use it for** list/detail layouts: Unibox list and thread, pipeline board and people board, conversation and details.

**What you provide**: `label` ("Resize conversation list"), `valueText` for screen readers ("260 pixels for the list"), `min`/`max`/`now` in pixels, `isResizing`, pointer handlers (`onPointerDown`/`Move`/`Up`), `onKeyDown` (arrow keys step the width) and `onReset` (double-click restores the default).

**Anatomy**: a 12px hit strip with a 1px `border` line that turns `primary` at 50% on hover and full `primary` on focus or drag, and a 12 × 48px grip pill in the middle.

## API

```ts
interface PanelSplitterProps {
    label: string;
    /** Human-readable state for screen readers, e.g. "320 pixels for the list". */
    valueText: string;
    min: number;
    max: number;
    now: number;
    isResizing: boolean;
    onPointerDown: (event: PointerEvent<HTMLElement>) => void;
    onPointerMove: (event: PointerEvent<HTMLElement>) => void;
    onPointerUp: (event: PointerEvent<HTMLElement>) => void;
    onKeyDown: (event: KeyboardEvent<HTMLElement>) => void;
    onReset: () => void;
    className?: string;
}
export declare function PanelSplitter({ label, valueText, min, max, now, isResizing, onPointerDown, onPointerMove, onPointerUp, onKeyDown, onReset, className, }: PanelSplitterProps): JSX.Element;
```

## Example

```html
<div id="root" class="p-6"></div>
<script>
(function () {
  var h = React.createElement, DC = window.DigitalCrew, I = DC.Icons;
function App() {
  var w = React.useState(260), drag = React.useState(false), start = React.useRef(null);
  function set(v) { w[1](Math.max(200, Math.min(420, v))); }
  return h("div", { className: "flex h-52 overflow-hidden rounded-lg border" },
    h("div", { style: { width: w[0] }, className: "shrink-0 p-4" },
      h("p", { className: "text-sm font-medium" }, "Conversations"),
      h("p", { className: "text-sm text-muted-foreground" }, "Drag the seam, use the arrow keys, or double-click to reset.")),
    h(DC.PanelSplitter, {
      label: "Resize conversation list", valueText: w[0] + " pixels for the list", min: 200, max: 420, now: w[0], isResizing: drag[0],
      onPointerDown: function (e) { start.current = { x: e.clientX, w: w[0] }; drag[1](true); e.currentTarget.setPointerCapture(e.pointerId); },
      onPointerMove: function (e) { if (start.current) set(start.current.w + e.clientX - start.current.x); },
      onPointerUp: function () { start.current = null; drag[1](false); },
      onKeyDown: function (e) { if (e.key === "ArrowLeft") set(w[0] - 16); if (e.key === "ArrowRight") set(w[0] + 16); },
      onReset: function () { w[1](260); } }),
    h("div", { className: "flex-1 p-4 bg-muted/40" }, h("p", { className: "text-sm font-medium" }, "Thread"), h("p", { className: "text-sm text-muted-foreground" }, "Claire Dubois · Re: annual plan")));
}
  ReactDOM.createRoot(document.getElementById("root")).render(h(DC.TooltipProvider, { delayDuration: 80 }, h(App)));
})();
</script>
```

## More in Layout

- [Accordion](/design/components/accordion.md): Stacked sections that expand one at a time (or several); height animates in 250ms on the smooth-out ease (`--acc-*`).
- [Card](/design/components/card.md): The raised surface for grouped content: `card` fill, `border`, `radius-xl` (14px), `shadow-sm`, 24px padding and gap.
- [Collapsible](/design/components/collapsible.md): Shows and hides one region under its trigger (Radix Collapsible); animates with the accordion tokens.
- [ContentSection](/design/components/content-section.md): The settings-page section: a title, a one-line description, a separator, then a scrolling body.
- [DataTableToolbar](/design/components/data-table-toolbar.md): The toolbar of Max's data-table kit (search, faceted filters, Reset and the View columns menu) and how the kit's pieces fit around a `Table`.
- [Main](/design/components/main.md): The page body of Max's app shell: a `<main>` with the standard page padding and, by default, a centred 7xl width.
- [ScrollArea](/design/components/scroll-area.md): A scroll container with thin themed scrollbars (10px track, `border`-coloured thumb) that appear on hover.
- [Separator](/design/components/separator.md): A 1px `border` hairline, horizontal or vertical (Radix Separator, decorative by default).
- [Table](/design/components/table.md): The data table primitive: 14px rows with `border` dividers, 40px header cells in medium weight, `muted` at 50% on hover and selection.
