Custom double-click behavior
Replace what happens when the user double-clicks on empty canvas by patching the select tool's Idle state at runtime.
import { StateNode, TLClickEventInfo, Tldraw } from 'tldraw'
import 'tldraw/tldraw.css'
// There's a guide at the bottom of this file!
// [1]
type IdleStateNode = StateNode & {
handleDoubleClickOnCanvas(info: TLClickEventInfo): void
}
export default function CustomDoubleClickBehaviorExample() {
return (
<div className="tldraw__editor">
<Tldraw
onMount={(editor) => {
// [2]
const selectIdleState = editor.getStateDescendant<IdleStateNode>('select.idle')
if (!selectIdleState) throw Error('SelectTool Idle state not found')
// [3]
selectIdleState.handleDoubleClickOnCanvas = function (_info: TLClickEventInfo) {
window.alert('double clicked on the canvas')
}
}}
/>
</div>
)
}
/*
The select tool's `Idle` state calls `handleDoubleClickOnCanvas` when the user double-clicks
on empty canvas (or on a shape that can't be edited). By default it creates a text shape and
starts editing it. Here we swap that method out at runtime for one that shows an alert.
[1]
The `Idle` class itself isn't exported from `tldraw`, and `handleDoubleClickOnCanvas` isn't
part of the public `StateNode` type, so we describe the shape we expect and cast to it.
[2]
`editor.getStateDescendant` walks the tool state tree by dotted path: `'select'` is the
select tool, `'select.idle'` is its idle child state. Because tools are singletons created
when the editor mounts, `onMount` is a safe place to patch them.
[3]
Assigning a `function` (rather than an arrow function) means `this` inside it is the state
node, the same as it would be for the original method. This replaces the default behavior
entirely; if you want to extend it instead, keep a reference to the original method and call
it from your replacement.
If all you want is to turn the default off, there's a simpler route: pass
`options={{ createTextOnCanvasDoubleClick: false }}` to `<Tldraw>`.
*/
By default, double-clicking on empty canvas creates a text shape and starts editing it. That
behavior lives in the handleDoubleClickOnCanvas method of the select tool's Idle state. This
example uses editor.getStateDescendant('select.idle') from onMount to grab that state and
replace the method with one that shows an alert.
Try double-clicking on the canvas. Double-clicking an editable shape still edits it as usual, but double-clicking a shape that can't be edited falls through to the same method, so it shows the alert too.
This example is hacky. Patching a built-in state's method is a lightweight way to tweak one
behavior without writing a whole custom tool, but handleDoubleClickOnCanvas is not public API and
can be renamed or removed in any release. If you only want to disable the default, pass
options={{ createTextOnCanvasDoubleClick: false }} to <Tldraw> instead. If you need different
behavior, write a custom select tool.