apps/docs/content/releases/v5.3.0.mdx
This release adds commenting: a set of new packages for anchored comment threads on the canvas, backed by comment records in the schema and sync support for non-document data. Commenting is the first piece of our new collaboration package, a separately licensed section of the SDK for premium collaboration features. The release also adds flipping for geo shapes, snapping and symmetric resizing while cropping images, an assets prop for TldrawImage, and a reactive Editor.getIsMounted() with a new unmount event. Viewport culling is faster on large pages, and there's a batch of fixes for crashes and interaction bugs across arrows, groups, and text.
Comments are now a first-class primitive in the SDK. @tldraw/commenting ships a batteries-included canvas comments layer: threads anchor to a point, a shape (precisely or imprecisely), a text range, a region, or the page. You can reply, edit, react, resolve, and delete comments. The pins drag to re-anchor, and ?comment=<id> deep links open a thread and bring the camera to its pin. Comment pins cluster together as you zoom out and separate back out as you zoom in.
Comment records live in @tldraw/tlschema as TLCommentThread, TLComment, and TLCommentReaction, and sync over a new generic object store in @tldraw/sync-core, so they ride alongside the document rather than inside it. On the server, @tldraw/sync-collaboration enforces write authorization, with a canModifyComment rule that lets a host widen the default owner-only permission. That way a workspace admin can moderate comments they don't own without granting anything beyond edit, delete, and resolve.
One rollout note: the comment record types ship with guard migrations, so once your server registers them, clients on an older SDK are rejected as too old and prompted to refresh. Roll out the upgraded client before or alongside the server change.
The layer is built to be taken apart. ThreadRow and ThreadActions are component slots, CommentListItem and sortSidebarRows are exported so a hand-built list can match the built-in one, and a host that supplies getThreadHref gets copy-link in the thread menu. On phones, the composer and the open thread stay above the software keyboard.
| Package | What it provides |
|---|---|
@tldraw/commenting | Canvas comments layer, comment UI components, and the comment tool |
@tldraw/mentions | @-mention picker and TipTap node, shared by comments and shape rich text |
@tldraw/collaboration | Umbrella package for the collaboration pieces |
@tldraw/sync-collaboration | Server-side write authorization for collaboration features |
See the commenting docs for setup.
usePassThroughMouseOverEvents from @tldraw/editor. It re-dispatched mouseover at .tl-canvas so shapes under a floating panel stayed hovered, but the canvas only wires onPointerEnter, so the re-dispatched event arrived at an element with no listener for it. (#9782)TLCommentThread, TLComment, and TLCommentReaction records to @tldraw/tlschema, with createCommentThread and createComment helpers, id helpers, validators, and commentSchemaRecords for registering them. (#9471, #9782)@tldraw/sync-core for syncing non-document records: objectTypes on the room and storage constructors, per-session TLObjectStoreAccess, getObjectsSnapshot(), onCommittedChanges, and an optional TLSyncStorage.getObjectsByIds(ids) for callers that need a few object-lane records rather than the whole lane. (#9471, #9782)objectAccess to the synced-remote member of RemoteTLStoreWithStatus, so a store from useSync reports whether the session can write object-lane records such as comments. If you construct that type yourself, in test mocks for example, you now need to supply objectAccess. (#9471)EditorPortal, EditorPortalProps, and useEditorPortalHost to @tldraw/editor, for portalling canvas-anchored content into a host the editor renders last so its DOM order doesn't depend on mount timing. (#9782)renderHtmlFromRichTextWithExtensions(richText, extensions) for rendering rich text outside a shape's editor config. renderHtmlFromRichText now fills every empty paragraph with a and keeps the paragraph's attributes, so an empty paragraph renders as `<p dir="auto"><TldrawImage snapshot={snapshot} assets={assetStore} />
unmount event to TLEventMap and make Editor.getIsMounted() a reactive value that tracks whether the editor's component is currently mounted. (#9472, #9483)coarseHitTestMargin option: fine pointers (mouse and trackpad) use a tighter 3px default, coarse pointers (touch and pen) use 4px. (#9492)ShapeUtil.onDuplicate(source, duplicate) callback, invoked by Editor.duplicateShapes and Editor.putContentOntoCurrentPage, so a shape can adjust its props when it is copied. Sticky notes now use it to attribute duplicated or pasted text to the current user instead of carrying over the original author. (#9566)TLGeoShape gains flipX and flipY props, matching the image shape, and a flip mirrors the shape's generated path. Geometry, hit-testing, the selection indicator, the canvas render, and SVG export all read from that path, so they stay in agreement. (#9530)overrides, instead of leaving an empty submenu trigger behind. (#9589)overflow says so. (#9698)about:blank#blocked. Dropping one now shows an error toast instead of failing validation on the bookmark shape. (#9598)onChildrenChange call when creating a shape directly within a parent shape. (#9455)getMetaKey() and getAccelKey(). (#9404)