Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/docs/content/getting-started/releases.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ We ship an experimental `tldraw-migrate` agent skill to let an agent help you up

## v5.x

- [v5.1](/releases/v5.1.0) - Page menu redesign, copy-styles shortcut, selectable locked shapes, public translation APIs, and performance improvements
- [v5.0](/releases/v5.0.0) - Custom themes, overlays, performance, extensiblity, and attribution

## v4.x
Expand Down
37 changes: 10 additions & 27 deletions apps/docs/content/releases/next.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,23 @@
title: Next release
description: Changes coming in the next release
author: tldraw
date: 05/06/2026
date: 06/03/2026
order: 0
status: published
last_version: v5.0.2
last_version: v5.1.0
---

This release redesigns the page menu around inline interaction, adds a keyboard shortcut to copy styles from a hovered shape, and adds a `selectLockedShapes` option for inspecting locked shapes, along with new public translation APIs, canvas performance improvements, and various rendering and UI bug fixes.

## What's new

### Page menu redesign ([#8836](https://github.com/tldraw/tldraw/pull/8836))

The page menu no longer has an explicit edit mode. Reorder pages by dragging a row directly, rename inline by double-clicking the label or pressing Enter, and drag the new resize handle at the bottom of the popover to adjust the list height — the height is persisted across sessions and a double-click on the handle resets it to the default. The current page is now indicated by a subtle background pill, the row submenu trigger reveals on hover, and the "Create new page" button is pinned to the footer of the popover.
This release simplifies multi-click handling down to a single double-click event — a breaking change for anyone relying on triple- or quadruple-click handlers — and fixes a number of canvas interaction bugs around pinch-zoom selection, pasting mid-gesture, note list editing, and zoom clamping.

## API changes

- Add a `selectLockedShapes` option to `TldrawOptions`. When enabled, locked shapes can be selected by left click or by brush/scribble selection while remaining protected from edits, moves, and deletes. ([#8860](https://github.com/tldraw/tldraw/pull/8860))
- Export `TldrawUiTranslationProvider`, `AssetUrlsProvider`, and `useAssetUrls` as public API so components like `TldrawSelectionForeground` can be rendered without the full `TldrawUiContextProvider`. ([#8909](https://github.com/tldraw/tldraw/pull/8909))
- Add `FontManager.dispose()`, `OverlayManager.dispose()`, and `OverlayUtil.dispose()` for cleaning up manager state across editor lifecycles. ([#8896](https://github.com/tldraw/tldraw/pull/8896))

## Improvements

- Add a `q` shortcut that copies the styles of the hovered shape and applies them to the next shape you create. ([#8917](https://github.com/tldraw/tldraw/pull/8917)) (contributed by [@kaneel](https://github.com/kaneel))
- Improve performance on busy canvases — `getRenderingShapes()` now skips its sort step when only shape props, not the set of shape ids, have changed. ([#8784](https://github.com/tldraw/tldraw/pull/8784))
- Improve drawing performance on pages with many shapes by skipping spatial index and culling recomputation when only shape props change. ([#8799](https://github.com/tldraw/tldraw/pull/8799), [#8804](https://github.com/tldraw/tldraw/pull/8804))
- 💥 Simplify multi-click handling to double-click only. `ClickManager` no longer tracks triple or quadruple clicks: the `triple_click` and `quadruple_click` events and the `onTripleClick` / `onQuadrupleClick` handlers have been removed, and `TLClickEventName` is now just `'double_click'`. ([#8897](https://github.com/tldraw/tldraw/pull/8897))

## Bug fixes

- Fix a misleading "license expired" console warning for perpetual licenses on covered versions. ([#8791](https://github.com/tldraw/tldraw/pull/8791))
- Fix inconsistent tooltip behavior on the video toolbar by using `TldrawUiToolbarButton` for the replace and download buttons. ([#8794](https://github.com/tldraw/tldraw/pull/8794))
- Fix the missing open-state hint on the page menu and zoom menu triggers when rendered outside the main toolbar. ([#8813](https://github.com/tldraw/tldraw/pull/8813))
- Mark the tldraw UI layer with `role="document"` so toolbars, menus, and dialogs stay reachable to mobile screen readers like VoiceOver and TalkBack, which do not announce the outer canvas `role="application"`. ([#8901](https://github.com/tldraw/tldraw/pull/8901))
- Fix selection edge resize handles overlapping corner handles, which made corners hard to grab on small shapes. ([#8926](https://github.com/tldraw/tldraw/pull/8926))
- Fix a bug where deleting a shape inside a group could move the group to a different z-index. ([#8925](https://github.com/tldraw/tldraw/pull/8925)) (contributed by [@kaneel](https://github.com/kaneel))
- Avoid console errors from calling `preventDefault` on non-cancelable events. ([#8910](https://github.com/tldraw/tldraw/pull/8910))
- Only log the missing-translation warning once per session instead of once per `useTranslation` consumer. ([#8909](https://github.com/tldraw/tldraw/pull/8909))
- Catch `image.decode()` rejections from the icon preload effect so they no longer surface as uncaught promise errors in the console. ([#8824](https://github.com/tldraw/tldraw/pull/8824))
- Fix the fill style dropdown trigger showing a misleading tooltip for the currently selected fill. ([#9023](https://github.com/tldraw/tldraw/pull/9023))
- Fix a two-finger pinch unintentionally changing the selection on touch devices. ([#9006](https://github.com/tldraw/tldraw/pull/9006))
- Pasting content while dragging, translating, resizing, or rotating no longer steals selection from the shape being manipulated. ([#8976](https://github.com/tldraw/tldraw/pull/8976))
- Fix a bug where pressing `Tab` while editing a list inside a note shape created a new note instead of indenting the list item. ([#8958](https://github.com/tldraw/tldraw/pull/8958))
- Fix the viewport shifting slightly when zooming past the minimum or maximum zoom level. ([#8957](https://github.com/tldraw/tldraw/pull/8957))
- Fix `debounce(...).cancel()` leaving an awaited call hanging forever; it now rejects the pending promise. ([#8683](https://github.com/tldraw/tldraw/pull/8683))
50 changes: 50 additions & 0 deletions apps/docs/content/releases/v5.1.0.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
title: v5.1.0
description: Page menu redesign, a copy-styles shortcut, a selectLockedShapes option, public translation APIs, and more
author: tldraw
date: 06/03/2026
order: 0
status: published
keywords:
- changelog
- release
- v5.1
- v5.1.0
- page-menu
- copy-styles
- locked-shapes
- translations
---

[View on GitHub](https://github.com/tldraw/tldraw/releases/tag/v5.1.0)

This release redesigns the page menu around inline interaction, adds a keyboard shortcut to copy styles from a hovered shape, and adds a `selectLockedShapes` option for inspecting locked shapes, along with new public translation APIs, canvas performance improvements, and various rendering and UI bug fixes.

## What's new

### Page menu redesign ([#8836](https://github.com/tldraw/tldraw/pull/8836))

The page menu no longer has an explicit edit mode. Reorder pages by dragging a row directly, rename inline by double-clicking the label or pressing Enter, and drag the new resize handle at the bottom of the popover to adjust the list height — the height is persisted across sessions and a double-click on the handle resets it to the default. The current page is now indicated by a subtle background pill, the row submenu trigger reveals on hover, and the "Create new page" button is pinned to the footer of the popover.

## API changes

- Add a `selectLockedShapes` option to `TldrawOptions`. When enabled, locked shapes can be selected by left click or by brush/scribble selection while remaining protected from edits, moves, and deletes. ([#8860](https://github.com/tldraw/tldraw/pull/8860))
- Export `TldrawUiTranslationProvider`, `AssetUrlsProvider`, and `useAssetUrls` as public API so components like `TldrawSelectionForeground` can be rendered without the full `TldrawUiContextProvider`. ([#8909](https://github.com/tldraw/tldraw/pull/8909))
- Add `FontManager.dispose()`, `OverlayManager.dispose()`, and `OverlayUtil.dispose()` for cleaning up manager state across editor lifecycles. ([#8896](https://github.com/tldraw/tldraw/pull/8896))

## Improvements

- Improve performance on busy canvases — `getRenderingShapes()` now skips its sort step when only shape props, not the set of shape ids, have changed. ([#8784](https://github.com/tldraw/tldraw/pull/8784))
- Improve drawing performance on pages with many shapes by skipping spatial index and culling recomputation when only shape props change. ([#8799](https://github.com/tldraw/tldraw/pull/8799), [#8804](https://github.com/tldraw/tldraw/pull/8804))

## Bug fixes

- Fix a misleading "license expired" console warning for perpetual licenses on covered versions. ([#8791](https://github.com/tldraw/tldraw/pull/8791))
- Fix inconsistent tooltip behavior on the video toolbar by using `TldrawUiToolbarButton` for the replace and download buttons. ([#8794](https://github.com/tldraw/tldraw/pull/8794))
- Fix the missing open-state hint on the page menu and zoom menu triggers when rendered outside the main toolbar. ([#8813](https://github.com/tldraw/tldraw/pull/8813))
- Mark the tldraw UI layer with `role="document"` so toolbars, menus, and dialogs stay reachable to mobile screen readers like VoiceOver and TalkBack, which do not announce the outer canvas `role="application"`. ([#8901](https://github.com/tldraw/tldraw/pull/8901))
- Fix selection edge resize handles overlapping corner handles, which made corners hard to grab on small shapes. ([#8926](https://github.com/tldraw/tldraw/pull/8926))
- Fix a bug where deleting a shape inside a group could move the group to a different z-index. ([#8925](https://github.com/tldraw/tldraw/pull/8925))
- Avoid console errors from calling `preventDefault` on non-cancelable events. ([#8910](https://github.com/tldraw/tldraw/pull/8910))
- Only log the missing-translation warning once per session instead of once per `useTranslation` consumer. ([#8909](https://github.com/tldraw/tldraw/pull/8909))
- Catch `image.decode()` rejections from the icon preload effect so they no longer surface as uncaught promise errors in the console. ([#8824](https://github.com/tldraw/tldraw/pull/8824))
40 changes: 39 additions & 1 deletion apps/docs/scripts/lib/generateSection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,12 @@ export function generateSection(section: InputSection, articles: Articles, index
? sectionUncategorizedArticles
: sectionCategoryArticles[category.id]

categoryArticles.sort(sortArticles).forEach((article, i) => {
const sortedArticles =
sectionId === 'releases'
? sortReleaseArticles(categoryArticles)
: categoryArticles.sort(sortArticles)

sortedArticles.forEach((article, i) => {
article.categoryIndex = i
article.sectionIndex = articleSectionIndex
assignToArticles(getArticleKey(article), article)
Expand Down Expand Up @@ -150,6 +155,39 @@ const sortArticles = (articleA: Article, articleB: Article) => {
: categoryIndexA - categoryIndexB
}

// Parse a release title like "v5.1.0" into a [major, minor, patch] tuple, or null
// for non-version pages (the "Next release" and "Migration skill" articles).
function getReleaseVersion(article: Article): [number, number, number] | null {
const match = /^v(\d+)\.(\d+)\.(\d+)$/.exec(article.title.trim())
if (!match) return null
return [Number(match[1]), Number(match[2]), Number(match[3])]
}

// The releases section can't rely on the generic title sort: version titles don't
// compare correctly as strings (e.g. "v3.10.0" < "v3.2.0") and the "Next release"
// and "Migration skill" pages need fixed positions. Order it explicitly so the
// sidebar and prev/next nav read: Next release, the latest version, Migration skill,
// then every other version newest-first.
function sortReleaseArticles(articles: Article[]): Article[] {
const next = articles.find((a) => a.path === '/releases/next')
const migration = articles.find((a) => a.path === '/releases/migration-skill')

const versions = articles
.filter((a) => a !== next && a !== migration)
.sort((a, b) => {
const [majorA, minorA, patchA] = getReleaseVersion(a) ?? [0, 0, 0]
const [majorB, minorB, patchB] = getReleaseVersion(b) ?? [0, 0, 0]
return majorB - majorA || minorB - minorA || patchB - patchA || a.title.localeCompare(b.title)
})

const ordered: Article[] = []
if (next) ordered.push(next)
if (versions.length > 0) ordered.push(versions[0])
if (migration) ordered.push(migration)
ordered.push(...versions.slice(1))
return ordered
}

function getArticleData({
articleId,
categoryId: categoryIdOverride,
Expand Down
8 changes: 8 additions & 0 deletions apps/docs/utils/ContentDatabase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,14 @@ export class ContentDatabase {
}
}

// The releases section is ordered newest-first (so the latest release and the
// "Next release" page sit at the top of the list), but its prev/next nav should
// still read chronologically: "previous" → the older release, "next" → the newer
// release. Newer releases have a lower sectionIndex, so swap the computed links.
if (article.sectionId === 'releases') {
return { prev: next ?? null, next: prev ?? null }
}

return { prev: prev ?? null, next: next ?? null }
}

Expand Down
2 changes: 1 addition & 1 deletion skills/shared/release-notes-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ When a PR is reverted, also remove the original PR's entry from `next.mdx` if it

## Team members (do not credit)

angrycaptain19, AniKrisn, ds300, kostyafarber, max-dra, mimecuvalo, MitjaBezensek, profdl, Siobhantldraw, steveruizok, tldrawdaniel, huppy-bot, github-actions, Somehats, todepond, Taha-Hassan-Git, alex-mckenna-1, max-drake
angrycaptain19, AniKrisn, ds300, kaneel, kostyafarber, max-dra, mimecuvalo, MitjaBezensek, profdl, Siobhantldraw, steveruizok, tldrawdaniel, danieljamesross, jsscclr, frolic, huppy-bot, github-actions, Somehats, todepond, Taha-Hassan-Git, alex-mckenna-1, max-drake

Credit community contributors with:

Expand Down
2 changes: 1 addition & 1 deletion skills/update-release-notes/shared/release-notes-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ When a PR is reverted, also remove the original PR's entry from `next.mdx` if it

## Team members (do not credit)

angrycaptain19, AniKrisn, ds300, kostyafarber, max-dra, mimecuvalo, MitjaBezensek, profdl, Siobhantldraw, steveruizok, tldrawdaniel, huppy-bot, github-actions, Somehats, todepond, Taha-Hassan-Git, alex-mckenna-1, max-drake
angrycaptain19, AniKrisn, ds300, kaneel, kostyafarber, max-dra, mimecuvalo, MitjaBezensek, profdl, Siobhantldraw, steveruizok, tldrawdaniel, danieljamesross, jsscclr, frolic, huppy-bot, github-actions, Somehats, todepond, Taha-Hassan-Git, alex-mckenna-1, max-drake

Credit community contributors with:

Expand Down
Loading