Clickable custom shape

A todo shape with a checkbox and text input that handle their own pointer events.

import { Tldraw } from 'tldraw'
import 'tldraw/tldraw.css'
import { myInteractiveShape } from './my-interactive-shape-util'

// There's a guide at the bottom of this file!

// [1]
const customShapeUtils = [myInteractiveShape]

export default function InteractiveShapeExample() {
	return (
		<div className="tldraw__editor">
			<Tldraw
				shapeUtils={customShapeUtils}
				onMount={(editor) => {
					editor.createShape({ type: 'my-interactive-shape', x: 100, y: 100 })
				}}
			/>
		</div>
	)
}

/*
[1]
The shape util array is defined outside the component so it keeps the same identity across
renders. See my-interactive-shape-util.tsx for the shape itself, which shows how to let a
shape handle its own pointer events (a checkbox and a text input) without the editor
selecting or dragging it.
*/

By default the editor handles all pointer events on the canvas, so clicking a shape selects it and dragging moves it. To let part of a shape handle its own interactions, set pointer-events: all on the shape's HTMLContainer and call stopPropagation() on the events you want to keep from reaching the canvas.

Try clicking the checkbox to toggle the todo and typing in the input. Once a todo is checked, the input becomes read-only and lets pointer events through, so clicking it selects the shape as usual. See my-interactive-shape-util.tsx for the shape.

Is this page helpful?
Prev
Custom shape with tldraw styles
Next
Custom handle snap reference