The `Designer` component is the heart of the `@shadcn/designer` package. It gives you the canvas, frame, tooling, and data model you need to build custom editors, from a single framed artboard to a multi-pane design suite.

## Quick start

Use `Designer`, `DesignerContent`, `DesignerCanvas`, and `DesignerFrame` together to render the default editor experience. This mirrors the setup used in the basic example.

```tsx
import * as React from "react"
import {
  Designer,
  DesignerCanvas,
  DesignerContent,
  DesignerFrame,
} from "@shadcn/designer"

export function CustomDesigner() {
  return (
    <Designer>
      <DesignerContent>
        <DesignerCanvas>
          <DesignerFrame />
        </DesignerCanvas>
      </DesignerContent>
    </Designer>
  )
}
```

> **Tip:** `Designer` is layout agnostic. Wrap it inside your own flex or grid containers to create headers, panels, and footers around the canvas.

  The `Designer` component currently targets a single frame workflow. Support for multiple frames is in development and will land soon.

## Layout primitives

- `DesignerContent` renders the scrollable workspace that holds the canvas.
- `DesignerCanvas` provides pan, zoom, and selection handling for all layers.
- `DesignerFrame` draws the editable artboard and renders the current layer tree.
- `DesignerStaticFrame` renders a fixed, read-only preview from layer data.
- `DesignerToolbar`, `DesignerPanel`, and `DesignerPane` help you compose custom UI around the canvas.

Combine these building blocks with your own UI from `@shadcn/ui` to design the editor shell that fits your product.

## Core props

| Prop | Type | Description |
| --- | --- | --- |
| `defaultLayers` | `Layer[]` | Pre-populated layers for uncontrolled mode. Useful for seeding from persisted data. |
| `layers` | `Layer[]` | Enables controlled mode. Mirror state updates with `onLayersChange`. |
| `onLayersChange` | `(layers: Layer[]) => void` | Called whenever the editor mutates layers. Required when `layers` is provided. |
| `layerTypes` | `readonly LayerType[]` | Extends or replaces the default layer registry. Tie custom renderers and tooling to your data. |
| `frameSize` | `{ width: number; height: number; unit?: Unit }` | Sets the initial dimensions and unit for `DesignerFrame`. Combine with unit actions for print workflows. |
| `unitSystem` | `Unit` | Overrides the global unit (px, in, mm, etc.). Drives rulers, snapping, and measurement UI. |
| `dpi` | `number` | Define dots per inch for pixel-to-unit conversions. |
| `mode` | `"single" | "multiple"` | Toggle between editing one layer at a time or multi-select workflows. |
| `keybindings` | `Record<string, Keybinding>` | Customize shortcuts or provide localized variations. |
| `debug` | `boolean` | Surface debug visuals while developing integrations. |
| `onMount` | `() => void` | Run side effects (analytics, focus) after the editor mounts. |

## Uncontrolled mode

`Designer` manages its own layer state when you pass `defaultLayers`. This is ideal when you only need to load an initial document.

```tsx
import * as React from "react"
import {
  Designer,
  DesignerCanvas,
  DesignerContent,
  DesignerFrame,
  type Layer,
} from "@shadcn/designer"

const DEFAULT_LAYERS: Layer[] = [
  {
    id: "layer-1",
    name: "Hero",
    type: "text",
    value: "Hero",
    cssVars: {
      "--width": "300px",
      "--height": "100px",
      "--content-font-size": "64px",
      "--content-font-weight": "700",
      "--content-color": "#000000",
      "--translate-x": "80px",
      "--translate-y": "56px",
    },
  },
]

export function DesignerWithDefaults() {
  return (
    <Designer defaultLayers={DEFAULT_LAYERS}>
      <DesignerContent>
        <DesignerCanvas>
          <DesignerFrame />
        </DesignerCanvas>
      </DesignerContent>
    </Designer>
  )
}
```

## Controlled mode

When you need to sync layers with your own state or a backend, switch to controlled mode by providing `layers` and `onLayersChange`.

```tsx
import * as React from "react"
import {
  Designer,
  DesignerCanvas,
  DesignerContent,
  DesignerFrame,
  type Layer,
} from "@shadcn/designer"

export function DesignerControlled() {
  const [layers, setLayers] = React.useState<Layer[]>([])

  return (
    <Designer
      layers={layers}
      onLayersChange={setLayers}
    >
      <DesignerContent>
        <DesignerCanvas>
          <DesignerFrame />
        </DesignerCanvas>
      </DesignerContent>
    </Designer>
  )
}
```

## Custom layer types

Augment the editor by extending `DEFAULT_LAYER_TYPES` with your own definitions. Use `createLayerType` so the layer value is inferred in `render`, then pass the final array to `Designer`.

```tsx
import * as React from "react"
import {
  DEFAULT_LAYER_TYPES,
  Designer,
  DesignerContent,
  DesignerCanvas,
  DesignerFrame,
  createLayerType,
} from "@shadcn/designer"
import { IconPlayerPlay } from "@tabler/icons-react"

const videoLayer = createLayerType({
  type: "video",
  name: "Video",
  icon: <IconPlayerPlay />,
  defaultValues: {
    name: "Video",
    value: {
      src: "https://cdn.example.com/video.mp4",
    },
    cssVars: {
      "--width": "320px",
      "--height": "180px",
      "--background-color": "#000000",
    },
  },
  keybinding: {
    key: "v",
    label: "V",
    labelMac: "V",
    description: "Add video layer",
    group: "New Layer",
  },
  render: (layer) => {
    return (
      <video
        controls
        style={layer.contentStyle}
        src={layer.value.src}
      />
    )
  },
})

const layerTypes = [...DEFAULT_LAYER_TYPES, videoLayer]

export function DesignerWithVideoLayer() {
  return (
    <Designer
      layerTypes={layerTypes}
    >
      <DesignerContent>
        <DesignerCanvas>
          <DesignerFrame />
        </DesignerCanvas>
      </DesignerContent>
    </Designer>
  )
}
```

For app-wide type safety, export the same `layerTypes` array from your layers folder and augment `DesignerLayerTypes` with `InferLayerTypes`, as shown in [Layers](/docs/concepts/layers).

## Composing the UI

Add panels, toolbars, and inspector panes around the canvas to create a full editor experience.

```tsx
import * as React from "react"
import {
  Designer,
  DesignerCanvas,
  DesignerContent,
  DesignerFrame,
  DesignerHeader,
  DesignerPanel,
  DesignerToolbar,
  DesignerToolbarGroup,
  DesignerToolbarButton,
} from "@shadcn/designer"
import { Button } from "@shadcn/ui/button"

export function DesignerWithShell() {
  return (
    <Designer>
      <DesignerHeader className="flex items-center justify-between gap-2 p-4">
        <div className="text-sm font-medium">Brand Poster</div>
        <div className="flex gap-2">
          <Button size="sm">Preview</Button>
          <Button size="sm" variant="outline">
            Export
          </Button>
        </div>
      </DesignerHeader>

      <DesignerToolbar className="flex items-center gap-2 px-4">
        <DesignerToolbarGroup className="flex items-center gap-2">
          <DesignerToolbarButton size="sm">Add</DesignerToolbarButton>
          <DesignerToolbarButton size="sm">Duplicate</DesignerToolbarButton>
        </DesignerToolbarGroup>
      </DesignerToolbar>

      <div className="grid flex-1 grid-cols-[1fr_320px] gap-4">
        <DesignerContent>
          <DesignerCanvas>
            <DesignerFrame />
          </DesignerCanvas>
        </DesignerContent>

        <DesignerPanel className="flex flex-col gap-6 p-4">
          <div>
            <p className="text-sm font-semibold">Layer</p>
            <p className="text-sm text-muted-foreground">Select a layer to edit properties.</p>
          </div>
        </DesignerPanel>
      </div>
    </Designer>
  )
}
```

## Next steps

- Walk through [Layers](../layers) to learn how layer data, transforms, and inspectors work together.
- Dive into [Unit System](../unit-system) for precision control over print and physical products.
- Explore the `/examples` directory for more complete editor shells, including print and marketing templates.