User Interface
The user interface in tldraw includes the menus, toolbars, keyboard shortcuts, and analytics events in the editor.
Hiding the UI
You can hide the default tldraw user interface entirely using the hideUi
prop. This turns off both the visuals as well as the keyboard shortcuts.
function Example() {
return <Tldraw hideUi />
}
Here's an example of what that looks like. Note that while you can't select any other tools using the keyboard shortcuts, you can still use the setCurrentTool
method to change the tool. If you open the console and enter:
editor.setCurrentTool('draw')
...then you can start drawing.
All of our user interface works by controlling the editor via its Editor
methods. If you hide the user interface, you can still use these same editor's methods to control the editor. Our custom user interface example shows this in action.
The source for these examples are available in the tldraw repository or in a sandbox here.
Overrides
The content of tldraw's menus can be controlled via the overrides
prop. This prop accepts a TLUiOverrides object, which has methods for each part of the user interface, such as the toolbar
or keyboardShortcutsMenu
.
Actions
The user interface has a set of shared actions
that are used in the menus and keyboard shortcuts. These actions can be overridden by passing a new set of actions to the overrides.actions
method.
To create, update, or delete actions, provide an actions
method that receives both the editor and the default actions and returns a mutated actions object.
const myOverrides: TLUiOverrides = {
actions(editor, actions) {
// You can delete actions, but remember to
// also delete the menu items that reference them!
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: '$u',
onSelect(source: any) {
// Whatever you want to happen when the action is run
window.alert('My new action just happened!')
},
}
return actions
},
}
The actions
object is a map of TLUiActionItems, with each item keyed under its id
.
Tools
Tools work in the same manner as actions. You can override the default tools by passing a tools
method that accepts the default tools object and returns a mutated version of that object.
const myOverrides: TLUiOverrides = {
tools(editor, tools) {
// Create a tool item in the ui's context.
tools.card = {
id: 'card',
icon: 'color',
label: 'tools.card',
kbd: 'c',
readonlyOk: false,
onSelect: () => {
// Whatever you want to happen when the tool is selected
editor.setCurrentTool('card')
},
}
return tools
},
}
The tools
object is a map of TLUiToolItems, with each item keyed under its id
.
Toolbar and Menus
The remaining overrides are for toolbar and the various menus: the main menu, actions menu, context menu, help menu, and the keyboard shortcuts menu.
Each of these overrides accepts a method that receives the default menu schema and returns a mutated version of that schema.
const myOverrides: TLUiOverrides = {
actions(editor, actions) {
// Create a new action or replace an existing one
actions['my-new-action'] = {
id: 'my-new-action',
label: 'My new action',
readonlyOk: true,
kbd: '$u',
onSelect(source: any) {
window.alert('My new action just happened!')
},
}
return actions
},
contextMenu(editor, contextMenu, { actions }) {
const newMenuGroup = menuGroup('my-items', newMenuItem)
contextMenu.unshift(newMenuItem)
return contextMenu
},
menu(editor, menu, { actions }) {
// using the findMenuItem helper
const fileMenu = findMenuItem(menu, ['menu', 'file'])
if (fileMenu.type === 'submenu') {
// add the new item to the file menu's children
const newMenuItem = menuItem(actions['my-new-action'])
fileMenu.children.unshift(newMenuItem)
}
return menu
},
}
A menu schema is an array of either submenus, groups, items, or custom items. Each group or submenu may include any of the other types as its children.
The menu schema is stateful. Referencing atomic properties (such as computed values in the editor) will cause the menu to update when those values change. If you wish for a menu item to disappear from the menu, you can return null
from the menu method. You can also provide additional options for each item, disabled
or checked
.
const myOverrides: TLUiOverrides = {
menu(editor, menu, { actions }) {
const selectedShapes = editor.getSelectedShapeIds().length
const newMenuGroup = menuGroup(
'my-actions',
selectedShapes > 0 ? menuItem(actions['action-a']) : null,
menuItem(actions['action-b'], { disabled: selectedShapes < 3 })
)
menu.unshift(newMenuGroup)
return menu
},
}
It's recommmended to explore the default menu schema in order to understand how menu items work.
Translations
The translations
method accepts a table of new translations. For example, if you wanted a tool to reference a key "tools.card"
, then you should at minimum provide an english translation for this key.
const myOverrides: TLUiOverrides = {
translations: {
en: {
'tools.card': 'Card',
},
},
}
Events
The Tldraw
component has a prop, onUiEvent
, that the user interface will call when certain events occur.
function Example() {
function handleEvent(name, data) {
// do something with the event
}
return <Tldraw onUiEvent={handleEvent} />
}
The onUiEvent
callback is called with the name of the event as a string and an object with information about the event's source (e.g. menu
or context-menu
) and possibly other data specific to each event, such as the direction in an align-shapes
event.
Note that onUiEvent
is only called when interacting with the user interface. It is not called when running commands manually against the app, e.g. calling Editor.alignShapes
will not call onUiEvent
.
See the tldraw repository for an example of how to customize tldraw's user interface.