Some checks failed
Deploy analytics worker / Deploy analytics worker to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
i18n upload strings / Upload latest strings (push) Failing after 1s
Deploy bemo / Deploy bemo to ${{ (github.ref == 'refs/heads/bemo-production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
Deploy grafana resources / ${{ github.event_name == 'push' && 'Deploy grafana resources' || 'Validate grafana resources (dry run)' }} (push) Failing after 0s
End to end tests (dotcom) / Check for relevant changes (push) Failing after 0s
End to end tests (examples) / Check for relevant changes (push) Failing after 0s
End to end tests (mermaid readability) / Check for relevant changes (push) Failing after 1s
End to end tests (perf) / Check for relevant changes (push) Failing after 0s
Publish editor extensions / Publish editor extensions (push) Failing after 1s
Publish SDK packages / Remove the publish-packages label (push) Has been skipped
Checks / Tests & checks (push) Has been cancelled
Checks / Build all projects (push) Has been cancelled
Deploy templates / Deploy templates (push) Has been cancelled
End to end tests (dotcom) / End to end tests (dotcom) (push) Has been cancelled
End to end tests (mermaid readability) / End to end tests (mermaid readability) (push) Has been cancelled
End to end tests (perf) / End to end tests (perf) (push) Has been cancelled
Deploy .com / Deploy dotcom to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Has been cancelled
End to end tests (examples) / End to end tests (examples) (push) Has been cancelled
Publish SDK packages / Publish SDK packages (push) Has been cancelled
Publish SDK packages / Tell user released version (push) Has been cancelled
Publish SDK packages / Publishes code templates to separate repositories (push) Has been cancelled
Publish SDK packages / Deploys the template demos with the new SDK version (push) Has been cancelled
168 lines
7.3 KiB
Plaintext
168 lines
7.3 KiB
Plaintext
---
|
|
title: Pages
|
|
created_at: 12/20/2025
|
|
updated_at: 12/20/2025
|
|
keywords:
|
|
- page
|
|
- pages
|
|
- multi-page
|
|
- navigation
|
|
reviewed_by: steveruizok
|
|
status: published
|
|
date: 12/20/2025
|
|
readability: 9
|
|
voice: 8
|
|
completeness: 9
|
|
accuracy: 9
|
|
notes: Add API link syntax for automatic linking. Tighten wording in a few places.
|
|
---
|
|
|
|
The pages system provides multiple independent sub-documents within a single tldraw document. Each page acts as a separate scene graph root with its own shapes, camera position, and selection state.
|
|
|
|
When you switch pages, the editor preserves your camera position and selected shapes on the previous page and restores the state you left on the new page. In collaborative sessions, users can see which pages their collaborators are viewing and follow them across page boundaries.
|
|
|
|
## How it works
|
|
|
|
Each page is a [TLPage](?) record in the store with a unique ID, a name for display, an index for ordering, and a `meta` object for your own data. Pages belong to the document scope: they persist across sessions and sync in collaborative environments. When you create a page, the editor automatically creates associated records for the camera position and instance page state.
|
|
|
|
The camera record associated with a page tracks viewport position and zoom for that page only. When you navigate to a different page, the editor switches to the camera for that page, so each user keeps their own view of each page. Camera options and constraints are editor-wide, not per page; they apply to whichever page is current.
|
|
|
|
The instance page state record tracks selection, editing state, focused groups, and other transient UI state unique to both a page and a browser session. This state belongs to the session scope and doesn't sync in collaborative environments. Each user maintains their own instance page state for each page they visit.
|
|
|
|
Pages are ordered. As with shapes, the page record's `index` property determines its order among other pages.
|
|
|
|
## Page methods
|
|
|
|
### Access
|
|
|
|
Get the current page or page ID with [Editor#getCurrentPage](?) and [Editor#getCurrentPageId](?):
|
|
|
|
```typescript
|
|
const currentPage = editor.getCurrentPage()
|
|
const currentPageId = editor.getCurrentPageId()
|
|
```
|
|
|
|
Access any page by ID with [Editor#getPage](?), or list them all with [Editor#getPages](?):
|
|
|
|
```typescript
|
|
import { TLPageId } from 'tldraw'
|
|
|
|
const page = editor.getPage('page:page1' as TLPageId)
|
|
const allPages = editor.getPages()
|
|
```
|
|
|
|
### Navigation
|
|
|
|
Switch to a different page using [Editor#setCurrentPage](?):
|
|
|
|
```typescript
|
|
editor.setCurrentPage('page:page2' as TLPageId)
|
|
```
|
|
|
|
When switching pages, the editor completes any in-progress interactions and stops following other users. The camera constraints are reapplied to ensure the new page's camera respects its configured bounds.
|
|
|
|
### Creating and deleting pages
|
|
|
|
Create new pages with [Editor#createPage](?), which ensures unique page names and proper index ordering:
|
|
|
|
```typescript
|
|
editor.createPage({ name: 'Wireframes' })
|
|
```
|
|
|
|
The editor enforces a maximum page count through the `maxPages` option (see [TldrawOptions](?), default: 40). Attempts to create pages beyond this limit are ignored. Set `maxPages` to 1 to disable multi-page UI entirely. All page mutations are no-ops when the editor is readonly.
|
|
|
|
Delete pages with [Editor#deletePage](?):
|
|
|
|
```typescript
|
|
editor.deletePage('page:page1' as TLPageId)
|
|
```
|
|
|
|
When deleting the current page, the editor switches to an adjacent page automatically. The last remaining page cannot be deleted. When a page is deleted, all shapes on that page are removed and the associated camera and instance page state records are cleaned up. If a collaborator deletes the page you're viewing, the editor moves you to another page.
|
|
|
|
### Duplicating pages
|
|
|
|
Use [Editor#duplicatePage](?) to copy an entire page including all its shapes and camera position:
|
|
|
|
```typescript
|
|
editor.duplicatePage('page:main' as TLPageId)
|
|
```
|
|
|
|
The duplicated page receives a copy of all shapes from the source page, preserving their positions, properties, and bindings between copied shapes. The camera position is copied from the source page and the editor switches to the new page. The new page's name appends " Copy" to the original page name. Like `createPage`, this respects `maxPages`.
|
|
|
|
### Renaming and updating pages
|
|
|
|
Rename a page with [Editor#renamePage](?):
|
|
|
|
```typescript
|
|
editor.renamePage('page:page1' as TLPageId, 'New Name')
|
|
```
|
|
|
|
For other updates, like changing the page's `meta`, use [Editor#updatePage](?):
|
|
|
|
```typescript
|
|
editor.updatePage({ id: 'page:page1' as TLPageId, meta: { description: 'Main design page' } })
|
|
```
|
|
|
|
## Working with shapes across pages
|
|
|
|
### Page-specific shape queries
|
|
|
|
Each page maintains its own shape hierarchy. Get shapes on the current page with [Editor#getCurrentPageShapes](?) and [Editor#getCurrentPageShapeIds](?):
|
|
|
|
```typescript
|
|
const shapes = editor.getCurrentPageShapes()
|
|
const shapeIds = editor.getCurrentPageShapeIds()
|
|
```
|
|
|
|
Get shape IDs from any page with [Editor#getPageShapeIds](?):
|
|
|
|
```typescript
|
|
const pageShapeIds = editor.getPageShapeIds('page:page2' as TLPageId)
|
|
```
|
|
|
|
These queries return only the top-level and nested shapes that belong to the specified page. Shapes are parented to pages through their `parentId` field.
|
|
|
|
### Moving shapes between pages
|
|
|
|
Transfer shapes from one page to another using [Editor#moveShapesToPage](?):
|
|
|
|
```typescript
|
|
import { TLShapeId } from 'tldraw'
|
|
|
|
editor.moveShapesToPage(
|
|
['shape:rect1' as TLShapeId, 'shape:circle2' as TLShapeId],
|
|
'page:page2' as TLPageId
|
|
)
|
|
```
|
|
|
|
The operation removes the shapes from the source page, switches to the destination page, and puts them there at the same position and with the same IDs. It then matches the source page's zoom, centers the camera on the moved shapes, and selects them.
|
|
|
|
Bindings between moved shapes are preserved. Bindings to shapes that stay behind are removed, and their binding utils receive `onBeforeIsolateFromShape` callbacks. If the move would push the destination page over the `maxShapesPerPage` option, nothing moves and the editor emits a `max-shapes` event.
|
|
|
|
## Collaboration and pages
|
|
|
|
In collaborative sessions, each user's current page is tracked through the presence system. Use [Editor#getCollaboratorsOnCurrentPage](?) to see who is on your page:
|
|
|
|
```typescript
|
|
const collaboratorsOnThisPage = editor.getCollaboratorsOnCurrentPage()
|
|
```
|
|
|
|
When following the viewport of a user who switches pages, your editor switches pages automatically to maintain the follow relationship. See [User following](/sdk-features/user-following) for details on cross-page following behavior.
|
|
|
|
## Undo and deep links
|
|
|
|
Undo and redo operations are document-wide, not page-specific. Undoing a page creation removes the page and all its shapes.
|
|
|
|
URLs can encode a page ID with the [deep links](/sdk-features/deep-links) API, so a document can open directly on a particular page.
|
|
|
|
## Related articles
|
|
|
|
- [Camera](/sdk-features/camera) - Camera options and constraints
|
|
- [User following](/sdk-features/user-following) - Following collaborators across pages
|
|
- [Deep links](/sdk-features/deep-links) - Encoding pages and viewports in URLs
|
|
|
|
## Related examples
|
|
|
|
- [Disable pages](/examples/configuration/disable-pages) - Disable page-related UI for single-page use cases by setting the `maxPages` option to 1.
|
|
- [Deep links](/examples/configuration/deep-links) - Create URLs that navigate to specific pages using the deep links API.
|