#10828·tldraw

Derive the canvas cursor from the active tool state

Author: kaneelCreated Sep 16, 2026Updated Sep 17, 2026
Labelssdkapi

The canvas cursor is stored as a value that tool states write when they are entered or handle events, rather than derived from the state the editor is actually in. So whenever a state is entered out of order, or a write is left over from an earlier state, the editor ends up in the right state with the wrong cursor. With the text tool locked, finishing a text edit returns to the text tool but showed an arrow instead of a crosshair (fixed in #10174), and earlier stale-cursor bugs like #8679 and #10430 are the same class. The goal is for the cursor to follow the active state reactively, so a stale cursor can't outlive the state that set it, while existing code that sets the cursor directly keeps working. A local prototype that derives the cursor from the active state passed the tldraw and editor test suites and fixed the #10174 case in the browser, but it silently overrode direct cursor writes made during those states, which breaks the cubic bezier example's hover cursor. Backward compatibility is therefore a design requirement, not a detail. A plan that keeps direct cursor writes working, checked against a local prototype, is in the comments.

Open questions

  1. Must direct cursor writes from existing apps and custom tools keep working unchanged, or is a behavior change acceptable if it ships with a migration note? They must keep working unchanged. The one intended change is that a cursor can no longer outlive the state that set it.
  2. Should this also make derived cursors the recommended pattern for custom tools (docs and examples), or stay an internal fix for the built-in tools? Deferred by user; not blocking implementation.
  3. Should #10174 land now as a targeted fix, or be closed in favour of this? Landed as the targeted fix. It also corrected the state chart itself (the select tool's idle state was left active under the text tool), which a derived cursor would not have fixed. This issue covers the broader stale-cursor class.

Confidence: 85%, ready to get started.