Documentation Index Fetch the complete documentation index at: https://mintlify.com/tldraw/tldraw/llms.txt
Use this file to discover all available pages before exploring further.
Menus and toolbars are the primary way users interact with the tldraw editor. This guide covers all the built-in menus and toolbars, how to customize them, and how to create your own.
Main toolbar
The main toolbar contains drawing tools and shape tools. It automatically handles overflow when there are too many items for the available space.
import { DefaultToolbar } from 'tldraw'
import 'tldraw/tldraw.css'
function MyToolbar () {
return < DefaultToolbar />
}
Customizing toolbar content:
import {
DefaultToolbar ,
SelectToolbarItem ,
HandToolbarItem ,
DrawToolbarItem ,
EraserToolbarItem ,
ArrowToolbarItem ,
TextToolbarItem ,
NoteToolbarItem ,
RectangleToolbarItem ,
EllipseToolbarItem ,
TriangleToolbarItem ,
DiamondToolbarItem ,
HexagonToolbarItem ,
StarToolbarItem ,
CloudToolbarItem ,
LineToolbarItem ,
FrameToolbarItem ,
} from 'tldraw'
function CustomToolbar () {
return (
< DefaultToolbar >
< SelectToolbarItem />
< HandToolbarItem />
< DrawToolbarItem />
< EraserToolbarItem />
< ArrowToolbarItem />
< TextToolbarItem />
< NoteToolbarItem />
< RectangleToolbarItem />
< EllipseToolbarItem />
< TriangleToolbarItem />
< DiamondToolbarItem />
< HexagonToolbarItem />
< StarToolbarItem />
< CloudToolbarItem />
< LineToolbarItem />
< FrameToolbarItem />
</ DefaultToolbar >
)
}
Vertical toolbar:
< DefaultToolbar orientation = "vertical" />
Controlling overflow behavior:
< DefaultToolbar
minItems = { 4 } // Minimum items before overflow
maxItems = { 8 } // Maximum items to show
minSizePx = { 310 } // Minimum size in pixels
maxSizePx = { 470 } // Maximum size in pixels
/>
Rich text toolbar
Floating toolbar shown when editing text shapes:
import { DefaultRichTextToolbar } from 'tldraw'
function CustomRichTextToolbar () {
return < DefaultRichTextToolbar />
}
Floating toolbar for image shapes:
import { DefaultImageToolbar } from 'tldraw'
function CustomImageToolbar () {
return < DefaultImageToolbar />
}
Floating toolbar for video shapes:
import { DefaultVideoToolbar } from 'tldraw'
function CustomVideoToolbar () {
return < DefaultVideoToolbar />
}
Main menu
The main dropdown menu accessed from the menu button:
import { DefaultMainMenu , DefaultMainMenuContent } from 'tldraw'
function CustomMainMenu () {
return (
< DefaultMainMenu >
< DefaultMainMenuContent />
</ DefaultMainMenu >
)
}
Adding custom menu items:
import {
DefaultMainMenu ,
DefaultMainMenuContent ,
TldrawUiMenuGroup ,
TldrawUiMenuItem ,
useEditor ,
} from 'tldraw'
function CustomMainMenu () {
const editor = useEditor ()
return (
< DefaultMainMenu >
< DefaultMainMenuContent />
< TldrawUiMenuGroup id = "custom" >
< TldrawUiMenuItem
id = "export-json"
label = "Export as JSON"
icon = "code"
onSelect = { () => {
const data = editor . store . serialize ( 'document' )
console . log ( 'Exported:' , data )
} }
/>
< TldrawUiMenuItem
id = "import-json"
label = "Import from JSON"
icon = "file"
onSelect = { () => {
// Import logic
} }
/>
</ TldrawUiMenuGroup >
</ DefaultMainMenu >
)
}
Right-click menu shown on the canvas:
import { DefaultContextMenu , DefaultContextMenuContent } from 'tldraw'
function CustomContextMenu () {
return (
< DefaultContextMenu >
< DefaultContextMenuContent />
</ DefaultContextMenu >
)
}
Adding custom context menu items:
import {
DefaultContextMenu ,
DefaultContextMenuContent ,
TldrawUiMenuGroup ,
TldrawUiMenuItem ,
useEditor ,
} from 'tldraw'
function CustomContextMenu () {
const editor = useEditor ()
return (
< DefaultContextMenu >
< DefaultContextMenuContent />
< TldrawUiMenuGroup id = "custom" >
< TldrawUiMenuItem
id = "custom-action"
label = "Custom Action"
icon = "heart"
onSelect = { () => {
const selectedShapes = editor . getSelectedShapes ()
console . log ( 'Context menu action:' , selectedShapes )
} }
/>
</ TldrawUiMenuGroup >
</ DefaultContextMenu >
)
}
Quick actions menu for undo, redo, etc.:
import { DefaultActionsMenu } from 'tldraw'
function CustomActionsMenu () {
return < DefaultActionsMenu />
}
Help and keyboard shortcuts menu:
import { DefaultHelpMenu } from 'tldraw'
function CustomHelpMenu () {
return < DefaultHelpMenu />
}
Zoom level controls:
import { DefaultZoomMenu } from 'tldraw'
function CustomZoomMenu () {
return < DefaultZoomMenu />
}
Page management menu:
import { DefaultPageMenu } from 'tldraw'
function CustomPageMenu () {
return < DefaultPageMenu />
}
Developer debugging menu:
import { DefaultDebugMenu } from 'tldraw'
function CustomDebugMenu () {
return < DefaultDebugMenu />
}
Basic clickable menu item:
import { TldrawUiMenuItem } from 'tldraw'
< TldrawUiMenuItem
id = "my-item"
label = "My Item"
icon = "edit"
kbd = "$e" // Keyboard shortcut display
disabled = { false }
onSelect = { () => console . log ( 'Selected' ) }
/>
Group of related menu items:
import { TldrawUiMenuGroup , TldrawUiMenuItem } from 'tldraw'
< TldrawUiMenuGroup id = "my-group" >
< TldrawUiMenuItem id = "item-1" label = "Item 1" />
< TldrawUiMenuItem id = "item-2" label = "Item 2" />
< TldrawUiMenuItem id = "item-3" label = "Item 3" />
</ TldrawUiMenuGroup >
Nested submenu:
import {
TldrawUiMenuSubmenu ,
TldrawUiMenuGroup ,
TldrawUiMenuItem ,
} from 'tldraw'
< TldrawUiMenuSubmenu
id = "my-submenu"
label = "More Options"
icon = "chevron-right"
>
< TldrawUiMenuGroup id = "submenu-group" >
< TldrawUiMenuItem id = "sub-item-1" label = "Sub Item 1" />
< TldrawUiMenuItem id = "sub-item-2" label = "Sub Item 2" />
</ TldrawUiMenuGroup >
</ TldrawUiMenuSubmenu >
Menu item that triggers a registered action:
import { TldrawUiMenuActionItem } from 'tldraw'
< TldrawUiMenuActionItem actionId = "copy" />
< TldrawUiMenuActionItem actionId = "paste" />
< TldrawUiMenuActionItem actionId = "delete" disabled = { noSelection } />
Checkbox menu item for toggles:
import { TldrawUiMenuCheckboxItem } from 'tldraw'
< TldrawUiMenuCheckboxItem
id = "toggle-grid"
label = "Show Grid"
checked = { isGridVisible }
onSelect = { () => setIsGridVisible ( ! isGridVisible ) }
/>
Checkbox item that triggers an action:
import { TldrawUiMenuActionCheckboxItem } from 'tldraw'
< TldrawUiMenuActionCheckboxItem
actionId = "toggle-grid"
checked = { isGridMode }
/>
Menu item for selecting a tool:
import { TldrawUiMenuToolItem } from 'tldraw'
< TldrawUiMenuToolItem
toolId = "select"
isSelected = { currentTool === 'select' }
/>
Tldraw provides pre-built menu item groups that you can use:
import {
ClipboardMenuGroup ,
ConversionsMenuGroup ,
EditMenuSubmenu ,
ArrangeMenuSubmenu ,
ReorderMenuSubmenu ,
SelectAllMenuItem ,
DeleteMenuItem ,
DuplicateMenuItem ,
GroupMenuItem ,
UngroupMenuItem ,
ZoomTo100MenuItem ,
ZoomToFitMenuItem ,
ZoomToSelectionMenuItem ,
} from 'tldraw'
// Use in your custom menus
< TldrawUiMenuGroup id = "edit" >
< ClipboardMenuGroup />
< SelectAllMenuItem />
< DeleteMenuItem />
</ TldrawUiMenuGroup >
< ConversionsMenuGroup />
< EditMenuSubmenu />
< ArrangeMenuSubmenu />
< ReorderMenuSubmenu />
Here’s a complete example of a custom menu with multiple groups:
import {
DefaultMainMenu ,
TldrawUiMenuGroup ,
TldrawUiMenuItem ,
TldrawUiMenuSubmenu ,
TldrawUiMenuActionItem ,
TldrawUiMenuCheckboxItem ,
ClipboardMenuGroup ,
useEditor ,
useValue ,
} from 'tldraw'
function CustomMainMenu () {
const editor = useEditor ()
const isGridMode = useValue (
'isGridMode' ,
() => editor . getInstanceState (). isGridMode ,
[ editor ]
)
return (
< DefaultMainMenu >
{ /* File operations */ }
< TldrawUiMenuGroup id = "file" >
< TldrawUiMenuItem
id = "new-document"
label = "New Document"
icon = "file"
kbd = "$n"
onSelect = { () => {
if ( confirm ( 'Clear canvas?' )) {
editor . selectAll ()
editor . deleteShapes ( editor . getSelectedShapeIds ())
}
} }
/>
< TldrawUiMenuItem
id = "open-document"
label = "Open Document"
icon = "folder"
kbd = "$o"
onSelect = { () => {
// Open file dialog logic
} }
/>
< TldrawUiMenuItem
id = "save-document"
label = "Save Document"
icon = "save"
kbd = "$s"
onSelect = { () => {
// Save logic
} }
/>
</ TldrawUiMenuGroup >
{ /* Edit operations */ }
< TldrawUiMenuGroup id = "edit" >
< ClipboardMenuGroup />
</ TldrawUiMenuGroup >
{ /* View options */ }
< TldrawUiMenuGroup id = "view" >
< TldrawUiMenuCheckboxItem
id = "toggle-grid"
label = "Show Grid"
checked = { isGridMode }
onSelect = { () => {
editor . updateInstanceState ({
isGridMode: ! isGridMode ,
})
} }
/>
< TldrawUiMenuActionItem actionId = "toggle-dark-mode" />
< TldrawUiMenuActionItem actionId = "toggle-focus-mode" />
</ TldrawUiMenuGroup >
{ /* Export submenu */ }
< TldrawUiMenuSubmenu
id = "export"
label = "Export"
icon = "external-link"
>
< TldrawUiMenuGroup id = "export-group" >
< TldrawUiMenuActionItem actionId = "export-as-svg" />
< TldrawUiMenuActionItem actionId = "export-as-png" />
< TldrawUiMenuItem
id = "export-json"
label = "Export as JSON"
icon = "code"
onSelect = { () => {
const data = editor . store . serialize ( 'document' )
const blob = new Blob (
[ JSON . stringify ( data , null , 2 )],
{ type: 'application/json' }
)
const url = URL . createObjectURL ( blob )
const a = document . createElement ( 'a' )
a . href = url
a . download = 'drawing.json'
a . click ()
} }
/>
</ TldrawUiMenuGroup >
</ TldrawUiMenuSubmenu >
{ /* Preferences */ }
< TldrawUiMenuGroup id = "preferences" >
< TldrawUiMenuActionItem actionId = "toggle-snap-mode" />
< TldrawUiMenuActionItem actionId = "toggle-tool-lock" />
< TldrawUiMenuActionItem actionId = "toggle-reduce-motion" />
</ TldrawUiMenuGroup >
</ DefaultMainMenu >
)
}
Build a completely custom toolbar using primitive components:
import {
TldrawUiToolbar ,
TldrawUiButton ,
TldrawUiButtonIcon ,
useEditor ,
useValue ,
} from 'tldraw'
import 'tldraw/tldraw.css'
function CustomToolbar () {
const editor = useEditor ()
const currentToolId = useValue (
'current tool' ,
() => editor . getCurrentToolId (),
[ editor ]
)
const tools = [
{ id: 'select' , icon: 'tool-pointer' },
{ id: 'hand' , icon: 'tool-hand' },
{ id: 'draw' , icon: 'tool-pencil' },
{ id: 'eraser' , icon: 'tool-eraser' },
{ id: 'text' , icon: 'tool-text' },
{ id: 'rectangle' , icon: 'geo-rectangle' },
{ id: 'ellipse' , icon: 'geo-ellipse' },
]
return (
< TldrawUiToolbar
orientation = "horizontal"
className = "my-custom-toolbar"
>
{ tools . map (( tool ) => (
< TldrawUiButton
key = { tool . id }
type = "tool"
isActive = { currentToolId === tool . id }
onClick = { () => editor . setCurrentTool ( tool . id ) }
>
< TldrawUiButtonIcon icon = { tool . icon } />
</ TldrawUiButton >
)) }
</ TldrawUiToolbar >
)
}
export default function App () {
return (
< Tldraw components = { { Toolbar: CustomToolbar } } />
)
}
Keyboard shortcuts
Add keyboard shortcuts to your custom actions:
const overrides : TLUiOverrides = {
actions ( editor , actions ) {
return {
... actions ,
'my-action' : {
id: 'my-action' ,
label: 'My Action' ,
kbd: '$e' , // Cmd/Ctrl + E
onSelect () {
// Action logic
},
},
'another-action' : {
id: 'another-action' ,
label: 'Another Action' ,
kbd: '$!d' , // Cmd/Ctrl + Shift + D
onSelect () {
// Action logic
},
},
}
},
}
Keyboard shortcut format:
$ = Cmd (Mac) / Ctrl (Windows/Linux)
! = Shift
? = Alt
Letters and numbers
Examples:
$c = Cmd/Ctrl + C
$!s = Cmd/Ctrl + Shift + S
?a = Alt + A
Next steps
UI components Complete reference of all UI components
Translations Learn about internationalization