Skip to content

Headless mode

Headless mode runs the full canvas engine and public API without any UI — the canvas, selection, transforms, history, export and events all work.

Enabling headless

js
new Editor({ target: '#app', ui: false })

Why headless?

  • Build a completely custom editing UI on top of the engine
  • Server-side design generation flows (render → export)
  • Embed the editor in environments where you control every pixel of chrome

Building your own UI

The public API is everything the built-in UI uses, so any custom UI is possible:

js
const editor = new Editor({ target: '#app', ui: false })

editor.on('ready', () => {
  editor.addText({ text: 'Headless design', fontSize: 64 })
})

// Your own controls:
document.querySelector('#addRect').onclick = () => {
  editor.addElement({ type: 'rect', w: 300, h: 160, fill: '#477cf5' })
}
document.querySelector('#bold').onclick = () => {
  editor.updateSelected({ fontWeight: 800 })
}
document.querySelector('#undo').onclick = () => editor.undo()
document.querySelector('#export').onclick = async () => {
  const dataUrl = await editor.exportImage('png', { scale: 2 })
  download(dataUrl)
}

Selection-driven UI

selection events keep custom controls in sync:

js
editor.on('selection', (selected) => {
  updateToolbarState(selected)
})

Custom history

Headless flows can also swap the history strategy (anything implementing push/undo/redo/reset):

js
new Editor({
  target: '#app',
  ui: false,
  history: myServerBackedHistory
})

Mixed setups

You don't have to go fully headless — disable individual modules instead:

js
new Editor({
  target: '#app',
  ui: { topbar: false, pagesBar: false } // keep the canvas + panels
})

See UI modules for per-module control.

Released under the MIT License.