v2.0.0
We just shipped @shadcn/designer v2.0.0 with typed layer definitions, first-class nested groups, group layout controls, and new hooks for working with layer values and meta.
See the upgrade guide for details on how to update your project to v2.0.0.
Here's everything that's new in v2.0.0:
- Type-Safe Layer Definitions
- Nested Layers and Groups
- Group Layout Controls
- Layer Value and Meta Hooks
- Shared Border, Corner, and Padding Controls
Type-Safe Layer Definitions
Layer types can now be defined with createLayerType. This keeps the type name and the shape of each layer's value and meta, so that you have fully typed layer definitions across your app including actions and hooks.
The setup has three parts:
- Define each custom layer with
createLayerType. - Export the final
layerTypesarray that your designer instance uses. - Register that array with
InferLayerTypesthrough module augmentation.
import {
DEFAULT_LAYER_TYPES,
createLayerType,
type InferLayerTypes,
} from "@shadcn/designer"
const chartLayer = createLayerType({
type: "chart",
name: "Chart",
defaultValues: {
name: "Chart",
value: {
type: "bar",
data: [],
},
meta: {
source: "manual",
},
},
render: (layer) => {
return <ChartRenderer value={layer.value} />
},
})
// Include the default layer types and your custom layers.
export const layerTypes = [...DEFAULT_LAYER_TYPES, chartLayer]
// Tell @shadcn/designer about the layer registry for this app.
declare module "@shadcn/designer" {
interface DesignerLayerTypes extends InferLayerTypes<typeof layerTypes> {}
}Once registered, the designer narrows APIs such as Layer, showForLayerTypes, useSetLayersValue, and useSetLayersMeta to your app's layer registry.
- See Type Safety and the
createLayerTypereference for the full setup. - See also the detailed guide for working with layers.
Nested Layers and Groups
Layers now support hierarchy through parentId, and group is a built-in layer type. You can group, ungroup, lock, reorder, and render nested documents.
- Added
parentIdto theLayertype. - Added the built-in
grouplayer type. - Added
GROUP_LAYERSandUNGROUP_LAYERSactions with default shortcuts. - Added
useLayerTree,useRootLayers, and layer tree utilities such asbuildLayerTree,getChildren,getDescendants, andgetAncestors. - Updated the layer tree pane with drag-and-drop reordering, nested selection, expandable groups, and group-aware lock behavior.
import { useLayerTree, useLayersAction } from "@shadcn/designer"
function GroupSelection({ selectedLayerIds }: { selectedLayerIds: string[] }) {
const layerTree = useLayerTree()
const layersAction = useLayersAction()
return (
<button onClick={() => layersAction("GROUP_LAYERS", selectedLayerIds)}>
Group {layerTree.length} root layers
</button>
)
}Use ⌘ G or Ctrl G to group selected layers, and ⌘ ⇧ G or Ctrl Shift G to ungroup.
Group Layout Controls
Group layers can now work as freeform or flex containers. The new layout actions expose display, direction, alignment, justification, gap, padding, and wrapping controls for group-specific inspector panels.
import {
ActionLayoutAlign,
ActionLayoutDirection,
ActionLayoutDisplay,
ActionLayoutGap,
ActionLayoutJustify,
ActionLayoutPadding,
ActionLayoutWrap,
DesignerPane,
DesignerPaneContent,
DesignerPaneTitle,
} from "@shadcn/designer"
function GroupPanel() {
return (
<DesignerPane showForLayerTypes={["group"]}>
<DesignerPaneTitle>Group</DesignerPaneTitle>
<DesignerPaneContent>
<ActionLayoutDisplay />
<ActionLayoutDirection />
<ActionLayoutAlign />
<ActionLayoutJustify />
<ActionLayoutGap />
<ActionLayoutPadding />
<ActionLayoutWrap />
</DesignerPaneContent>
</DesignerPane>
)
}Layer Value and Meta Hooks
useSetLayersValue and useSetLayersMeta provide typed setters for custom layer state. They accept a layer ID, an array of IDs, a layer object, or an array of layer objects, and support updater functions plus { history: false } for internal changes.
import { useSelectedLayers, useSetLayersMeta, useSetLayersValue } from "@shadcn/designer"
function ChartActions() {
const selectedLayers = useSelectedLayers()
const setLayersValue = useSetLayersValue()
const setLayersMeta = useSetLayersMeta()
const chartLayers = selectedLayers.filter((layer) => layer.type === "chart")
return (
<div>
<button onClick={() => setLayersValue(chartLayers, { type: "line", data: [] })}>
Line
</button>
<button
onClick={() =>
setLayersMeta(chartLayers, (prev) => ({
...prev,
source: "toolbar",
}))
}
>
Mark source
</button>
</div>
)
}See the useSetLayersValue and useSetLayersMeta references for target forms and generic usage.
Shared Border, Corner, and Padding Controls
The border, corner, and padding actions have been rebuilt around shared control behavior. They now handle mixed values across multi-selection, expose grouped and per-side controls, and share the same input model used by other numeric designer actions.
ActionCornersupports grouped radius editing and independent corner values.ActionPaddingsupports grouped padding and per-side padding.ActionBordersupports border width and color controls with shared multi-selection behavior.useSharedValuesis available for custom controls that need the same "all selected values match" behavior.
See the upgrade guide for upgrading your project to v2.0.0.
Restructured Docs, llms.txt, and Markdown
We've reorganized the docs and added support for LLMs and markdown.
Docs
The docs are now split into four sections: Concepts, Guides, Examples, and Reference. Old URLs redirect automatically.
llms.txt
We've added /llms.txt and /llms-full.txt endpoints for LLMs and AI tools. Every docs page is also available as markdown by appending .md to the URL. You'll find a "View as Markdown" link in the sidebar on each page.
v1.1.0
We just tagged @shadcn/designer v1.1.0 with a new unit system and unified Designer Tool API for managing canvas tools.
Unit System
We now let you work in pixels, millimeters, inches, centimeters, or points with DPI-aware conversions.
- Introduced hooks for reacting to unit changes:
useUnitSystem,useSetUnitSystem,useDPI, anduseSetDPI. - Added
ActionUnitSelectorfor swapping units directly from the toolbar. - Added a shared
unitslibrary with helpers liketoPixels,fromPixels,parseValueWithUnit, andformatValueplusDEFAULT_DPIandDPI_PRESETSpresets. - Updated editor defaults to store
unitSystemanddpi, convert paper sizes from millimeters, and clamp dimension inputs at0. - Refined dimension displays to show converted values with trimmed decimals and localized unit abbreviations.
import { useUnitSystem, useSetUnitSystem } from "@shadcn/designer"
function UnitSwitcher() {
const unitSystem = useUnitSystem()
const setUnitSystem = useSetUnitSystem()
return (
<div className="flex items-center gap-2">
<span>Units: {unitSystem}</span>
<button onClick={() => setUnitSystem("mm")}>Millimeters</button>
</div>
)
}Example
This example demonstrates how to use the unit system to display and work with measurements in different units.
Designer Tool
We've introduced a new tool selection system that allows you to switch between different interaction modes on the canvas. This release includes two core tools:
- Move Tool (V) - The default tool for selecting, moving, resizing, and rotating layers
- Hand Tool (H) - Pan around the canvas without selecting or moving layers
Hooks
useDesignerTool() - Get the currently active tool
import { useDesignerTool } from "@shadcn/designer"
function ToolIndicator() {
const tool = useDesignerTool()
return (
<div>
Active: {tool === "move" ? "Move Tool" : "Hand Tool"}
</div>
)
}useSetDesignerTool() - Change the active tool programmatically
import { useSetDesignerTool } from "@shadcn/designer"
function ToolSwitcher() {
const setTool = useSetDesignerTool()
return (
<div>
<button onClick={() => setTool("move")}>Move (V)</button>
<button onClick={() => setTool("hand")}>Hand (H)</button>
</div>
)
}ActionToolbarTool
Dropdown toolbar button for switching between tools
import { ActionToolbarTool } from "@shadcn/designer"
<DesignerToolbar>
<DesignerToolbarGroup>
<ActionToolbarTool />
</DesignerToolbarGroup>
</DesignerToolbar>See the Hooks Reference for complete API documentation.
Example
Use the Cursor and Hand buttons in the toolbar to switch between the move and hand tools.
Input Scrubber
The InputGroup component now supports scrubbing for faster adjustments without losing precision.
- Hold the mouse button and drag to scrub an input value.
- Added a
useScrubberhook that handles pointer locking, acceleration, and modifier shortcuts for fine or coarse adjustments. - Exposed the hook through the designer entry point so custom controls can share the same interaction model as built-in actions.
- Bundled a visual scrubber cursor that renders while dragging to make state changes easier to track.
import * as React from "react"
import { useScrubber } from "@shadcn/designer"
function DimensionScrubber() {
const { scrubProps, value } = useScrubber({
value: 120,
onChange: (next) => console.log("Width", next),
})
return (
<button className="flex items-center gap-2" {...scrubProps}>
Width: {value}px
</button>
)
}Continuous Button Press
We've added hold-to-repeat controls to make numeric inputs feel more responsive.
- Added a continuous press controller that emits repeated
onChangeevents while increment or decrement buttons remain pressed. - Integrated the behavior into
InputNumber, matching keyboard repeat cadence and respecting min/max constraints. - Tuned acceleration so long presses ramp quickly without overshooting small adjustments.
v1.0.0
We're excited to announce the release of @shadcn/designer v1.0.0 (stable). If you do not have a license, you can get one here.
Here's a list of the new features and improvements:
- mode - new
modeprop to the<Designer />component to switch between different layer modes. See the docs for more information. - onMount - We've added a new
onMountprop to the<Designer />component to run a callback when the designer is mounted. Useful for doing additional setup when the designer is ready. - defaultLayers - the
layersprop has been renamed todefaultLayersfor uncontrolled components. - layers and onLayersChange - We've added new props for controlled
<Designer />components. - We've also introduced a layer signature optimization to reduce the number of re-renders.
- We've improved layer snapping to be more accurate.
See the roadmap for what's coming next.
Thank you to all the early adopters who have been using the designer and providing feedback: Mikkel, Sebastian, Piotr, Santosh, Jenny, Alex, Maria, David K., David E., and Sarah.