--- title: Actions created_at: 12/25/2025 updated_at: 12/29/2025 keywords: - actions - commands - keyboard shortcuts - menus - overrides - customization status: published date: 12/25/2025 readability: 8 voice: 8 completeness: 9 accuracy: 9 notes: Interface definition shows property order different from source. Helper table has slight differences from implementation details. --- Actions are named operations that users trigger from menus, keyboard shortcuts, or custom UI. Each action bundles an identifier, display metadata (label, icon, keyboard shortcut), and a handler function. Actions let you define operations like "undo", "group", or "export as PNG" once and invoke them from multiple places with consistent behavior. ```tsx import { Tldraw, TLUiOverrides } from 'tldraw' import 'tldraw/tldraw.css' const overrides: TLUiOverrides = { actions(editor, actions, helpers) { // Add a custom action actions['show-selection-count'] = { id: 'show-selection-count', label: 'action.show-selection-count', kbd: 'shift+c', onSelect(source) { const count = editor.getSelectedShapeIds().length helpers.addToast({ title: `${count} shapes selected` }) }, } return actions }, } export default function App() { return (
) } ``` The `tldraw` package includes nearly 100 default actions covering editing, arrangement, export, zoom, and preferences. You can override any of these or add your own through the `overrides` prop, typed as [TLUiOverrides](?). ## How actions work Actions live in a React context inside the tldraw UI. When the UI mounts, it registers all default actions, applies any overrides you've provided, and makes them available through the [useActions](?) hook. Menus and toolbars look up actions by ID and render them with their labels, icons, and keyboard shortcuts. Each action has an `onSelect` handler that receives a source parameter indicating where it was triggered: ```tsx const actions = useActions() const duplicateAction = actions['duplicate'] // Trigger programmatically duplicateAction.onSelect('toolbar') ``` Keyboard shortcuts are bound automatically. The [useKeyboardShortcuts](?) hook parses each action's `kbd` property and registers hotkey handlers. When a shortcut fires, it calls the action's `onSelect` with `'kbd'` as the source. ## Action structure The [TLUiActionItem](?) interface defines what an action contains: | Property | Description | | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | Unique identifier for the action (e.g., `'duplicate'`, `'zoom-in'`) | | `label` | Translation key for display text. Can be a string or an object mapping contexts to different keys (see [Context-sensitive labels](#context-sensitive-labels)) | | `icon` | Icon name from tldraw's icon set, or a custom React element | | `kbd` | Keyboard shortcut string. Use commas to bind several combinations, e.g. `'cmd+g,ctrl+g'` (see [Keyboard shortcuts](#keyboard-shortcuts)) | | `readonlyOk` | When `true`, the action works in readonly mode. Defaults to `false` | | `checkbox` | When `true`, renders as a toggle with a checkmark indicator in menus | | `isRequiredA11yAction` | When `true`, the keyboard shortcut works even when shortcuts are normally disabled (e.g., while editing a shape). Used for accessibility actions | | `onSelect` | Handler called when the action is triggered. Receives a [TLUiEventSource](?) indicating the trigger origin (`'kbd'`, `'menu'`, `'toolbar'`, etc.) | ## Accessing actions Use the [useActions](?) hook to get all registered actions: ```typescript import { useActions } from 'tldraw' function MyComponent() { const actions = useActions() return ( ) } ``` The hook returns a record mapping action IDs to action objects. You can iterate over it to build custom menus or filter actions by property. ## Default actions The default actions cover most editing operations you'd expect in a canvas application. Some common ones, by category: | Category | Action ids | | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Editing | `undo`, `redo`, `duplicate`, `delete`, `copy`, `cut`, `paste` | | Grouping | `group`, `ungroup` | | Arrangement | `bring-to-front`, `bring-forward`, `send-backward`, `send-to-back`, `align-left`, `align-center-horizontal`, `align-right`, `distribute-horizontal`, `distribute-vertical` | | Export | `export-as-svg`, `export-as-png`, `copy-as-svg`, `copy-as-png` | | Zoom | `zoom-in`, `zoom-out`, `zoom-to-100`, `zoom-to-fit`, `zoom-to-selection`, `select-zoom-tool` | | Preferences | `toggle-dark-mode`, `toggle-snap-mode`, `toggle-grid`, `toggle-focus-mode` | The full list is in the [default actions source](https://github.com/tldraw/tldraw/blob/main/packages/tldraw/src/lib/ui/context/actions.tsx). Most actions guard themselves inside their handlers. For example, `group` and the arrangement actions do nothing unless shapes are selected and the select tool is active. ## Overriding actions Pass an `overrides` prop to customize actions. The override function receives the editor, the default actions, and helper utilities: ```typescript import { Tldraw, TLUiOverrides } from 'tldraw' const overrides: TLUiOverrides = { actions(editor, actions, helpers) { // Modify existing action actions['duplicate'].kbd = 'cmd+shift+d,ctrl+shift+d' // Disable an action by removing it delete actions['print'] return actions }, } function App() { return } ``` The `copy`, `cut`, and `paste` shortcuts are handled by native clipboard events rather than the `kbd` system, so changing their `kbd` has no effect. ### Modifying behavior To change what an action does, replace its `onSelect` handler: ```typescript const overrides: TLUiOverrides = { actions(editor, actions, helpers) { const originalDuplicate = actions['duplicate'].onSelect actions['duplicate'].onSelect = async (source) => { console.log('Duplicating shapes...') await originalDuplicate(source) console.log('Done!') } return actions }, } ``` You can call the original handler before or after your custom logic, or replace it entirely. ### Adding custom actions Add new actions by inserting them into the actions record: ```typescript const overrides: TLUiOverrides = { actions(editor, actions, helpers) { actions['my-custom-action'] = { id: 'my-custom-action', label: 'action.my-custom-action', kbd: 'cmd+shift+k,ctrl+shift+k', icon: 'external-link', onSelect(source) { const shapes = editor.getSelectedShapes() console.log('Custom action on', shapes.length, 'shapes') }, } return actions }, } ``` Custom actions integrate with the keyboard shortcut system automatically. To add them to menus, override the menu components; see [Actions in menus](#actions-in-menus) and the [custom menus example](/examples/ui/custom-menus). ### Using helper utilities The override function receives a `helpers` object ([TLUiOverrideHelpers](?), the return value of [useDefaultHelpers](?)): ```typescript const overrides: TLUiOverrides = { actions(editor, actions, helpers) { actions['show-toast'] = { id: 'show-toast', label: 'action.show-toast', onSelect(source) { helpers.addToast({ title: 'Hello!', description: 'This is a custom action.', }) }, } return actions }, } ``` Available helpers: | Helper | Description | | ----------------------- | ------------------------------------ | | `addToast` | Show a toast notification | | `removeToast` | Remove a specific toast | | `clearToasts` | Remove all toasts | | `addDialog` | Open a dialog | | `removeDialog` | Close a specific dialog | | `clearDialogs` | Close all dialogs | | `msg` | Get a translated string by key | | `isMobile` | Boolean indicating mobile breakpoint | | `insertMedia` | Open file picker and insert media | | `replaceImage` | Replace selected image with new file | | `replaceVideo` | Replace selected video with new file | | `printSelectionOrPages` | Print selection or all pages | | `cut` | Cut selected shapes to clipboard | | `copy` | Copy selected shapes to clipboard | | `paste` | Paste from clipboard | | `copyAs` | Copy shapes as SVG or PNG | | `exportAs` | Export shapes as SVG, PNG, or JSON | | `getEmbedDefinition` | Get embed info for a URL | ## Keyboard shortcuts Shortcuts use a simple string format with modifier keys separated by `+`. Use commas to bind several combinations to the same action. Every combination is active on every platform; the conventional `cmd+…,ctrl+…` pair covers Mac and everything else, and only the shortcut hint shown in menus ([TldrawUiKbd](?)) is platform-specific: ```typescript kbd: 'cmd+g,ctrl+g' // Cmd+G or Ctrl+G kbd: 'shift+1' // Shift+1 kbd: 'cmd+shift+s,ctrl+shift+s' // Cmd+Shift+S or Ctrl+Shift+S ``` Modifiers are `cmd` (alias `meta`), `ctrl`, `shift`, and `alt` (alias `option`). Special keys include `del`, `backspace`, `enter`, `escape`, `space`, and the arrow keys (`left`, `right`, `up`, `down`). To bind the `+` key itself, double the trailing plus: `cmd++`. That matches an unshifted `+` key (German, Nordic and similar layouts, or the numpad). On layouts where `+` is shift plus another key, such as US, write `cmd+shift++`, which is the same binding as `cmd+shift+=`. Shortcuts match the character the browser reports for the key press, not the physical keycap, with two exceptions: shifted number-row keys match by position, so write them as `shift+` on every layout, and when the reported character is non-ASCII (Cyrillic, Greek, macOS Option dead keys) matching falls back to the physical key's US QWERTY character, so `cmd+z` still works on a Russian layout. With shift held, the shifted and unshifted US spellings are the same binding, so `shift+:` and `shift+;` both fire when the browser reports `:` with shift held. Bind what the keyboard emits, not what the keycap says: on French AZERTY the `:` key emits `/` with shift held, so bind `shift+/`; on Japanese JIS the `^` key emits `~`, so bind `shift+~`. The characters `!`, `?` and `$` are reserved as legacy modifier markers and cannot be used as keys. Shortcuts only fire while the editor is focused and the key event does not target a text input. They are also disabled when a menu is open, a shape is being edited, the editor has a crashing error, or the user has disabled keyboard shortcuts in preferences. In readonly mode, only actions with `readonlyOk` are bound. Actions marked with `isRequiredA11yAction: true` bypass the disabled check for accessibility purposes. ## Actions in menus The default UI uses [TldrawUiMenuActionItem](?) to render actions in menus: ```typescript import { TldrawUiMenuActionItem, TldrawUiMenuGroup } from 'tldraw' function CustomMenu() { return ( ) } ``` This component looks up the action by ID and renders it with the correct label, icon, and shortcut hint. Pass `disabled` yourself if the item should be disabled. For toggle actions, use [TldrawUiMenuActionCheckboxItem](?) with a `checked` prop. ## Context-sensitive labels Some actions show different labels depending on where they appear. The `label` property can be an object mapping menu context types ([TLUiMenuContextType](?), plus `default`) to translation keys: ```typescript actions['export-as-svg'] = { id: 'export-as-svg', label: { default: 'action.export-as-svg', menu: 'action.export-as-svg.short', 'context-menu': 'action.export-as-svg.short', }, // ... } ``` The menu component uses the appropriate label based on its context. If no specific label exists for a context, it falls back to `default`. ## Tracking action usage The `source` parameter tells you where the action was triggered. Use this for analytics: ```tsx actions['custom-action'] = { id: 'custom-action', label: 'action.custom', kbd: 'cmd+k,ctrl+k', onSelect(source) { trackEvent('custom-action', { source }) // source: 'kbd', 'menu', 'context-menu', 'toolbar', 'quick-actions', 'zoom-menu', etc. }, } ``` ## Related examples - [Action overrides](/examples/ui/action-overrides) - Add custom actions and modify existing action shortcuts using the overrides prop. - [Keyboard shortcuts](/examples/ui/keyboard-shortcuts) - Change keyboard shortcuts for tools and actions. - [Custom menus](/examples/ui/custom-menus) - Build custom menus that use actions with proper labels and shortcuts.