snapshot of https://github.com/tldraw/tldraw.git (main, 2026-09-23; blobs > 131072B omitted)
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

This commit is contained in:
upstream-mirror
2026-09-23 16:12:52 +05:00
commit a774ac673a
4541 changed files with 770499 additions and 0 deletions

View File

@@ -0,0 +1,321 @@
---
title: UI components
created_at: 12/17/2025
updated_at: 3/25/2026
keywords:
- ui
- components
- toolbar
- menu
- customization
status: published
date: 3/25/2026
readability: 8
voice: 8
completeness: 9
accuracy: 10
notes: ''
---
The `tldraw` package includes a complete React-based UI: the menus, toolbars, panels, and dialogs that users interact with when creating and editing content. The UI is composed of named component slots that you can override or hide one at a time.
The UI connects to the editor through React hooks and context providers. Components update automatically when editor state changes, so you can replace individual parts of the interface without reimplementing the logic that connects UI actions to editor operations.
## How it works
### Component slot architecture
The UI divides the screen into distinct layout zones:
```
┌─────────────────────────────────────────────────────────┐
│ Top Panel │
├────────────┬──────────────────────────┬─────────────────┤
│ Left │ Canvas │ Right │
│ Panel │ │ Panel │
├────────────┴──────────────────────────┴─────────────────┤
│ Bottom Panel │
└─────────────────────────────────────────────────────────┘
```
The top zone contains the main menu, helper buttons (like "Back to content"), an empty top panel slot, and the share and style panels. The bottom zone houses navigation controls, the main toolbar with drawing tools, and the help menu (if you provide one). On desktop, the style panel appears in the top-right zone; on mobile it moves into a popover opened from the toolbar.
Each zone can host multiple components. The toolbar includes the tool selector, tool-specific options, and the tool lock button.
### Context providers and state management
The UI establishes a hierarchy of React context providers. At the root, [TldrawUiContextProvider](?) coordinates the other providers and applies your overrides. Specialized providers handle translations, tooltips, dialogs, toasts, UI events, accessibility announcements, breakpoints for responsive behavior, and the component registry.
The actions and tools providers turn editor methods into UI actions with labels, icons, and keyboard shortcuts. When you click a toolbar button, the component calls an action from context, which invokes the editor method. The same action can be triggered from the toolbar, a menu, or a keyboard shortcut. See [Actions](/sdk-features/actions) for details.
### Reactive UI updates
UI components read editor state through hooks like [useEditor](?) and [useValue](?). These hooks use the editor's reactive signal system to re-render when relevant state changes. The style panel uses [useRelevantStyles](?) to decide which style controls to show for the current selection: select a different shape and the panel updates.
## Key components
### Component slots
The UI defines several component slots you can override or hide. The `Toolbar` holds the tool buttons. The `TopPanel` is an empty top-center slot with no default component; use it for your own UI like a document title or sync status. The `StylePanel` shows style controls for the selected shapes. The `MenuPanel` (top-left) groups the main menu, the page menu, and quick actions. The `NavigationPanel` (bottom-left) provides zoom controls and the minimap toggle. `HelperButtons` appear based on editor state, such as "Back to content" when the camera is far from shapes.
Each slot is optional. Pass `null` to hide a component, or pass your own React component to replace the default. A few slots have no default: `TopPanel` and `HelpMenu` are `null` unless you provide a component (use [DefaultHelpMenu](?) to opt in to the built-in help menu), and `SharePanel` and `CursorChatBubble` only render when collaboration UI is enabled.
### Slot props
The UI portion of the `components` prop is shaped by [TLUiComponents](?). Every key is optional: use `null` to hide that slot, or pass a React component. When a slot has a documented props type in the table below, import that type from `tldraw` and type your replacement as `React.ComponentType<…>` (or implement the matching props). When the props column says **none**, the SDK does not declare extra props for that slot beyond what a plain `ComponentType` allows.
| Slot | Props (import from `tldraw`) |
| ------------------------- | ----------------------------------------------------------------------------- |
| `ContextMenu` | [TLUiContextMenuProps](?) |
| `ActionsMenu` | [TLUiActionsMenuProps](?) |
| `HelpMenu` | [TLUiHelpMenuProps](?) |
| `ZoomMenu` | [TLUiZoomMenuProps](?) |
| `MainMenu` | [TLUiMainMenuProps](?) |
| `Minimap` | none |
| `StylePanel` | [TLUiStylePanelProps](?) |
| `PageMenu` | none |
| `NavigationPanel` | none |
| `Toolbar` | none |
| `RichTextToolbar` | [TLUiRichTextToolbarProps](?) |
| `ImageToolbar` | none |
| `VideoToolbar` | none |
| `KeyboardShortcutsDialog` | [TLUiKeyboardShortcutsDialogProps](?) |
| `QuickActions` | [TLUiQuickActionsProps](?) |
| `HelperButtons` | [TLUiHelperButtonsProps](?) |
| `DebugPanel` | none |
| `DebugMenu` | none |
| `MenuPanel` | none |
| `TopPanel` | none |
| `SharePanel` | none |
| `CursorChatBubble` | none |
| `Dialogs` | none |
| `Toasts` | none |
| `A11y` | none |
| `FollowingIndicator` | none |
| `PeopleMenu` | none (default component: optional `children` via [DefaultPeopleMenuProps](?)) |
| `PeopleMenuAvatar` | [TLUiPeopleMenuAvatarProps](?) |
| `PeopleMenuFacePile` | [TLUiPeopleMenuFacePileProps](?) |
| `PeopleMenuItem` | [TLUiPeopleMenuItemProps](?) |
| `UserPresenceEditor` | none |
This table is an index; the authoritative list and types remain [TLUiComponents](?) in the API reference and in the package typings.
### UI hooks
Components access editor functionality through specialized hooks.
[useEditor](?) returns the editor instance, with direct access to all editor methods and state.
[useActions](?) returns the UI actions (copy, paste, delete, and so on) with their labels, icons, and keyboard shortcuts. Call an action's `onSelect` from your custom UI.
[useTools](?) returns the available tools with their metadata. The toolbar uses this to render tool buttons.
[useRelevantStyles](?) returns the styles relevant to the current selection and their values. It powers the style panel.
[useBreakpoint](?) returns a numeric breakpoint index (0-7) matching the [PORTRAIT_BREAKPOINT](?) constants. Compare against values like `PORTRAIT_BREAKPOINT.MOBILE` or `PORTRAIT_BREAKPOINT.TABLET_SM` to adapt layout for different screen sizes.
## Hiding the UI
You can hide the default tldraw user interface entirely using the `hideUi` prop. This hides the visual UI only: keyboard shortcuts and clipboard handling keep working.
```tsx
import { Tldraw } from 'tldraw'
import 'tldraw/tldraw.css'
export default function App() {
return (
<div style={{ position: 'fixed', inset: 0 }}>
<Tldraw hideUi />
</div>
)
}
```
With the UI hidden, you can still control the editor programmatically through [Editor](?) methods. Open the console and try:
```ts
editor.setCurrentTool('draw')
```
All of tldraw's user interface works by controlling the editor via its methods. If you hide the user interface, you can still use these same methods to control the editor. See the [custom user interface example](/examples/ui/custom-ui) for this in action.
## Extension points
### Overriding components
Override individual components by passing them to the `components` prop:
```tsx
import { Tldraw, useEditor, useTools } from 'tldraw'
import 'tldraw/tldraw.css'
function CustomToolbar() {
const editor = useEditor()
const tools = useTools()
return (
<div className="my-toolbar">
{Object.values(tools).map((tool) => (
<button key={tool.id} onClick={() => editor.setCurrentTool(tool.id)}>
{tool.label}
</button>
))}
</div>
)
}
export default function App() {
return (
<div style={{ position: 'fixed', inset: 0 }}>
<Tldraw
components={{
Toolbar: CustomToolbar,
}}
/>
</div>
)
}
```
The `useTools` hook returns an object mapping tool IDs to [TLUiToolItem](?) objects. Each tool item contains metadata like `id`, `label`, `icon`, and `kbd` (keyboard shortcut).
### Hiding components
Pass `null` to hide a component entirely. This is useful for focused experiences that don't need the full default UI:
```tsx
<Tldraw
components={{
PageMenu: null,
DebugMenu: null,
NavigationPanel: null,
}}
/>
```
See the [UI components hidden example](/examples/ui/ui-components-hidden) for a complete list of hideable components.
## Overrides
Control tldraw's actions, tools, and translations with the `overrides` prop. This prop accepts a [TLUiOverrides](?) object, which has methods for `actions` and `tools`, and a `translations` property.
### Actions
The user interface has a set of shared actions used in the menus and keyboard shortcuts. Override these by providing an `actions` method that receives the editor, the [default actions](https://github.com/tldraw/tldraw/blob/main/packages/tldraw/src/lib/ui/context/actions.tsx), and a helpers object, then returns a mutated actions object. See [Actions](/sdk-features/actions) for the full story.
```tsx
import { Tldraw, TLUiOverrides } from 'tldraw'
import 'tldraw/tldraw.css'
const myOverrides: TLUiOverrides = {
actions(editor, actions, helpers) {
// Delete an action (remember to also delete any menu items that reference it)
delete actions['insert-embed']
// Create a new action or replace an existing one
actions['my-new-action'] = {
id: 'my-new-action',
label: 'My new action',
readonlyOk: true,
kbd: 'cmd+shift+u,ctrl+shift+u',
onSelect(source) {
window.alert('My new action just happened!')
},
}
return actions
},
}
export default function App() {
return (
<div style={{ position: 'fixed', inset: 0 }}>
<Tldraw overrides={myOverrides} />
</div>
)
}
```
The `actions` object is a map of [TLUiActionItem](?)s, keyed by their `id`. See the [action overrides example](/examples/ui/action-overrides) for more.
### Tools
Override tools the same way you override actions. Provide a `tools` method that accepts the editor, the [default tools object](https://github.com/tldraw/tldraw/blob/main/packages/tldraw/src/lib/ui/hooks/useTools.tsx), and a helpers object, then returns a mutated version.
```tsx
const myOverrides: TLUiOverrides = {
tools(editor, tools, helpers) {
// Create a tool item in the UI's context
tools.card = {
id: 'card',
icon: 'geo-rectangle',
label: 'tools.card',
kbd: 'c',
onSelect: () => {
editor.setCurrentTool('card')
},
}
return tools
},
}
```
The `tools` object is a map of [TLUiToolItem](?)s, keyed by their `id`. See the [add tool to toolbar example](/examples/ui/add-tool-to-toolbar) for a complete implementation.
### Translations
The `translations` property accepts a table of new translations. If you add a tool with `label: 'tools.card'`, you need to provide an English translation for that key:
```tsx
const myOverrides: TLUiOverrides = {
translations: {
en: {
'tools.card': 'Card',
},
},
}
```
See [internationalization](/sdk-features/internationalization) for more about tldraw's translation system.
## UI events
The [Tldraw](?) component has an `onUiEvent` prop that fires when users interact with the UI:
```tsx
import { Tldraw, TLUiEventHandler } from 'tldraw'
import 'tldraw/tldraw.css'
export default function App() {
const handleUiEvent: TLUiEventHandler = (name, data) => {
console.log('UI event:', name, data)
}
return (
<div style={{ position: 'fixed', inset: 0 }}>
<Tldraw onUiEvent={handleUiEvent} />
</div>
)
}
```
The callback receives the event name as a string and an object with the event's `source` (e.g. `menu` or `context-menu`) and other data specific to each event, such as the `operation` in an `align-shapes` event.
Note that `onUiEvent` only fires for UI interactions. Calling [Editor#alignShapes](?) directly won't trigger this callback. See the [UI events example](/examples/events/ui-events) for more.
## Related articles
- [UI primitives](/sdk-features/ui-primitives) - Use tldraw's button, menu, dialog, and other UI components in your custom interfaces
- [Overlay utils](/sdk-features/overlay-utils) - Customize canvas overlays like brushes, indicators, snaps, scribbles, and collaborator cursors
- [Internationalization](/sdk-features/internationalization) - Customize translations and add new languages
- [Tools](/sdk-features/tools) - Learn how tools work and create your own
## Related examples
- [Replace the entire UI](/examples/ui/custom-ui) - Build a completely custom toolbar UI while using the editor's functionality
- [Custom canvas components](/examples/ui/custom-components) - Override individual canvas components like the background and grid
- [Hide the entire UI](/examples/ui/hide-ui) - Use hideUi to hide the entire default interface
- [Hide UI components](/examples/ui/ui-components-hidden) - Selectively hide specific UI components
- [Changing menus](/examples/ui/custom-menus) - Create custom menus using tldraw's menu system
- [Vertical toolbar](/examples/ui/vertical-toolbar) - Switch to a vertical toolbar layout
- [Add tool to toolbar](/examples/ui/add-tool-to-toolbar) - Add a custom tool to the toolbar
- [UI events](/examples/events/ui-events) - Listen to UI events like tool selection and menu interactions