Designer
Learn how to use the designer component.
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.
import * as React from "react"
import {
Designer,
DesignerCanvas,
DesignerContent,
DesignerFrame,
} from "@shadcn/designer"
export function CustomDesigner() {
return (
<Designer className="flex h-svh flex-col gap-4">
<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 a transformable artboard. Add multiple frames or swap inDesignerStaticFrame
when you want a fixed preview.DesignerToolbar
,DesignerPanel
, andDesignerPane
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 | 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"` |
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. |
Seeding layers in uncontrolled mode
Designer
manages its own layer state when you pass defaultLayers
. This is ideal when you only need to load an initial document.
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: "frame",
value: null,
cssVars: {
"--width": "640px",
"--height": "480px",
"--background-color": "#dbeafe",
"--translate-x": "80px",
"--translate-y": "56px",
},
},
]
export function DesignerWithDefaults() {
return (
<Designer defaultLayers={DEFAULT_LAYERS} className="flex h-[720px] flex-col gap-4">
<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
.
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}
className="flex h-[720px] flex-col gap-4"
>
<DesignerContent>
<DesignerCanvas>
<DesignerFrame />
</DesignerCanvas>
</DesignerContent>
</Designer>
)
}
Custom layer types
Augment the editor by extending DEFAULT_LAYER_TYPES
with your own definition. Supply defaults, keyboard shortcuts, and a render function that outputs React nodes.
import * as React from "react"
import {
DEFAULT_LAYER_TYPES,
Designer,
DesignerContent,
DesignerCanvas,
DesignerFrame,
type LayerType,
} from "@shadcn/designer"
import { IconPlayerPlay } from "@tabler/icons-react"
const VIDEO_LAYER_TYPE = {
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}
/>
)
},
} satisfies LayerType
export function DesignerWithVideoLayer() {
return (
<Designer
layerTypes={[...DEFAULT_LAYER_TYPES, VIDEO_LAYER_TYPE]}
className="flex h-[720px] flex-col gap-4"
>
<DesignerContent>
<DesignerCanvas>
<DesignerFrame />
</DesignerCanvas>
</DesignerContent>
</Designer>
)
}
Composing the UI
Add panels, toolbars, and inspector panes around the canvas to create a full editor experience.
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 className="flex h-svh flex-col gap-4">
<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 to learn how layer data, transforms, and inspectors work together.
- Dive into Unit System for precision control over print and physical products.
- Explore the
/examples
directory for more complete editor shells, including print and marketing templates.