Focus the editor
Control the editor's focus with focus(), blur(), and autoFocus to gate keyboard shortcuts and scroll capture.
import { useState } from 'react'
import { Editor, Tldraw, useValue } from 'tldraw'
import 'tldraw/tldraw.css'
import './editor-focus.css'
// There's a guide at the bottom of this file!
export default function EditorFocusExample() {
const [editor, setEditor] = useState<Editor | null>(null)
// [1]
const isFocused = useValue('isFocused', () => editor?.getIsFocused() ?? false, [editor])
return (
<div className="editor-focus-example">
<input type="text" placeholder="Test me" />
<p>
You should be able to type in this text input without triggering editor shortcuts, even when
the editor is focused.
</p>
<h2>Controlled focus</h2>
<div className="editor-focus-example__controls">
<input
id="focus"
type="checkbox"
checked={isFocused}
onChange={(e) => {
// [2]
if (e.target.checked) {
editor?.focus()
} else {
editor?.blur()
}
}}
/>
<label htmlFor="focus">Focus</label>
</div>
<p>
The checkbox focuses and blurs the editor. Clicking on the canvas also focuses it, which is
why the checkbox follows the editor's own focus state.
</p>
<p>
When the editor is focused, its keyboard shortcuts work and scrolling over it moves the
canvas. When it is not, shortcuts are ignored and the page scrolls instead.
</p>
<div className="editor-focus-example__editor">
{/* [3] */}
<Tldraw autoFocus={false} onMount={setEditor} />
</div>
</div>
)
}
/*
[1]
`editor.getIsFocused()` is reactive, so reading it through `useValue` keeps the checkbox in sync
whether focus changed through the checkbox or by clicking the canvas.
[2]
`editor.focus()` and `editor.blur()` set the editor's focus state and, by default, also focus or
blur the container element. Pass `{ focusContainer: false }` / `{ blurContainer: false }` to
change only the editor's state.
[3]
`autoFocus={false}` stops the editor from grabbing focus when it mounts, which matters when the
canvas is one of several things on a page (or one of several editors).
*/
The editor's focus decides whether its keyboard shortcuts respond and whether wheel events pan the canvas. It is related to, but not the same as, the browser's notion of focus (the document's active element). The browser's focus can't be relied on for this: iframes aren't descendants of their parents, and many menus are portalled elsewhere in the document, so checking whether the active element is inside the Tldraw element isn't reliable.
That leaves focus management to you, especially with more than one editor on a page. This example mounts the editor with autoFocus={false} and drives focus with editor.focus() and editor.blur() from a checkbox that stays in sync via editor.getIsFocused(). Try typing in the text input while the editor is focused (shortcuts shouldn't fire), and toggle the checkbox to see scrolling switch between the page and the canvas.