Essential Hooks

The designer hooks you will reach for most often when building custom editor UI.

Most custom designer UI is built from a small set of hooks. The full hooks reference lists everything, but this page covers the hooks that usually matter first when you are wiring up toolbars, panes, custom controls, and document actions.

Reading the document

Use these hooks when your UI needs to reflect the current document or selection.

HookUse it for
useLayersReading the raw layer array.
useLayersWithStylesReading layers with computed style and contentStyle.
useLayerTreeRendering a nested layer tree.
useSelectedLayersReading the selected layer objects.
useSelectedLayerTypesShowing controls for the selected layer types.

Most inspector controls start with useSelectedLayers:

import { useSelectedLayers } from "@shadcn/designer"
 
function SelectedLayersList() {
  const selectedLayers = useSelectedLayers()
 
  if (!selectedLayers.length) {
    return null
  }
 
  // Render a list of the selected layers.
  return (
    <ul>
      {selectedLayers.map((layer) => (
        <li key={layer.id}>{layer.name}</li>
      ))}
    </ul>
  )
}

Updating layer data

Layer data falls into four buckets: common layer properties, layer-specific values, metadata, and CSS variables.

HookUse it for
useSetLayersValueUpdating the value of one or more layers.
useSetLayersMetaUpdating the meta of one or more layers.
useSetLayersPropertyUpdating shared layer fields like name, isLocked
createLayerCssVarAction + useLayerCssVarActionBuilding controls for CSS variables like fill, size, position, and typography.

Use useSetLayersValue for custom layer values:

import { useSelectedLayers, useSetLayersValue } from "@shadcn/designer"
 
function ShapeTypeAction() {
  const selectedLayers = useSelectedLayers()
  const setLayersValue = useSetLayersValue()
  const shapeLayers = selectedLayers.filter((layer) => layer.type === "shape")
 
  return (
    <button
      onClick={() => setLayersValue(shapeLayers, { type: "circle" })}
      disabled={shapeLayers.length === 0}
    >
      Circle
    </button>
  )
}

useSetLayersValue and useSetLayersMeta accept a layer ID, an array of layer IDs, a layer object, or an array of layer objects. If you only have IDs, pass the layer type as a generic so TypeScript can check the value:

setLayersValue<"shape">(selectedLayerIds, { type: "square" })
setLayersMeta<"shape">(selectedLayerIds, { source: "toolbar" })

Use the updater form when the next value depends on the previous value:

setLayersValue<"shape">("shape-1", (prev) => ({
  ...prev,
  type: prev.type === "circle" ? "square" : "circle",
}))

Use useSetLayersProperty for common fields that are not specific to one layer type:

const setLayersProperty = useSetLayersProperty()
 
setLayersProperty(selectedLayerIds, "isLocked", true)

Do not use useSetLayersProperty to update cssVars. Use createLayerCssVarAction and useLayerCssVarAction instead.

For visual properties stored in cssVars, prefer a CSS variable action. It automatically reads and writes the value across the current selection.

import {
  createLayerCssVarAction,
  useLayerCssVarAction,
} from "@shadcn/designer"
 
const fill = createLayerCssVarAction("--background-color", "#000000")
 
function FillAction() {
  const [value, setValue] = useLayerCssVarAction(fill)
 
  return (
    <input
      type="color"
      value={value}
      onChange={(event) => setValue(event.target.value)}
    />
  )
}

All of these setters record undo history by default. Pass { history: false } when you need an internal update that should not create an undo step:

setLayersValue<"shape">("shape-1", { type: "circle" }, { history: false })

Creating and deleting layers

Use these hooks when a control changes the structure of the document.

HookUse it for
useAddLayersCreating one or more layers from layer input.
useDeleteLayersDeleting layers by ID.

Use useAddLayers when you are creating new layer objects yourself:

const addLayers = useAddLayers()
 
addLayers([
  {
    type: "text",
    name: "Text",
    value: "Hello world",
    cssVars: {
      "--translate-x": "120px",
      "--translate-y": "120px",
    },
  },
])

Canvas and editor controls

These hooks control the designer shell rather than the document data itself.

HookUse it for
useDesignerActionRunning canvas-level commands like zoom, undo, redo, redraw, and deselect.
useDesignerTool / useSetDesignerToolReading or switching between the move and hand tools.
useZoom / useSetZoomReading or setting the current zoom.
useFrameSize / useSetFrameSizeReading or setting the frame size.
useUnitSystem / useSetUnitSystemReading or setting the active unit system.
useDPI / useSetDPIReading or setting DPI for unit conversion.

useDesignerAction is useful for toolbar buttons that map directly to designer commands:

const designerAction = useDesignerAction()
 
designerAction("ZOOM_IN")
designerAction("ZOOM_FIT")
designerAction("UNSELECT_ALL")

For controls that need to show the current value, pair the read and write hooks:

const zoom = useZoom()
const setZoom = useSetZoom()
 
setZoom(Math.min(zoom + 0.1, 3))

History

Use the dedicated history hooks when you are building undo and redo UI.

HookUse it for
useUndoUndoing the last recorded layer change.
useRedoRedoing the next recorded layer change.
useCanUndoDisabling undo UI when there is nothing to undo.
useCanRedoDisabling redo UI when there is nothing to redo.
function HistoryActions() {
  const undo = useUndo()
  const redo = useRedo()
  const canUndo = useCanUndo()
  const canRedo = useCanRedo()
 
  return (
    <div>
      <button onClick={undo} disabled={!canUndo}>
        Undo
      </button>
      <button onClick={redo} disabled={!canRedo}>
        Redo
      </button>
    </div>
  )
}

Next Steps