首页
/ 用 tldraw SDK 隐藏内置 UI:TLUiComponents 置空与 hideUi 深度指南

用 tldraw SDK 隐藏内置 UI:TLUiComponents 置空与 hideUi 深度指南

2026-09-08 16:43:48作者:滑思眉Philip

本文围绕 tldraw SDK 官方示例 ui-components-hidden 展开:tldraw 把默认界面拆解为 TLUiComponents 中的一个个“插槽(slot)”,将任一插槽设为 null 即可精确移除对应的菜单、面板或工具条;若想一次性去掉整套默认 UI、只保留画布与编辑器能力,则用 hideUi prop。读完你将掌握「按需裁剪」与「完全无头(headless)」两种 UI 隐藏方案,并能在此基础上用自己的 React 组件替换被隐藏的部分。

背景:tldraw 默认 UI 的分层架构

tldraw 编辑器(<Tldraw>)由编辑内核(canvas、shapes、tools、store)与默认 UI 外壳(工具栏、菜单、面板、对话框等)组成。默认 UI 并非铁板一块,而是全部注册在一个中央配置对象中。

从源码看,这个配置对象定义于 packages/tldraw/src/lib/ui/context/components.tsxTLUiComponents 接口:

/** @public */
export interface TLUiComponents {
	ContextMenu?: ComponentType<TLUiContextMenuProps> | null
	ActionsMenu?: ComponentType<TLUiActionsMenuProps> | null
	HelpMenu?: ComponentType<TLUiHelpMenuProps> | null
	ZoomMenu?: ComponentType<TLUiZoomMenuProps> | null
	MainMenu?: ComponentType<TLUiMainMenuProps> | null
	Minimap?: ComponentType | null
	StylePanel?: ComponentType<TLUiStylePanelProps> | null
	PageMenu?: ComponentType | null
	NavigationPanel?: ComponentType | null
	Toolbar?: ComponentType | null
	RichTextToolbar?: ComponentType<TLUiRichTextToolbarProps> | null
	ImageToolbar?: ComponentType | null
	VideoToolbar?: ComponentType | null
	KeyboardShortcutsDialog?: ComponentType<TLUiKeyboardShortcutsDialogProps> | null
	QuickActions?: ComponentType<TLUiQuickActionsProps> | null
	HelperButtons?: ComponentType<TLUiHelperButtonsProps> | null
	DebugPanel?: ComponentType | null
	DebugMenu?: ComponentType | null
	MenuPanel?: ComponentType | null
	TopPanel?: ComponentType | null
	SharePanel?: ComponentType | null
	CursorChatBubble?: ComponentType | null
	Dialogs?: ComponentType | null
	Toasts?: ComponentType | null
	A11y?: ComponentType | null
	FollowingIndicator?: ComponentType | null
	PeopleMenu?: ComponentType | null
	PeopleMenuAvatar?: ComponentType<TLUiPeopleMenuAvatarProps> | null
	PeopleMenuItem?: ComponentType<TLUiPeopleMenuItemProps> | null
	PeopleMenuFacePile?: ComponentType<TLUiPeopleMenuFacePileProps> | null
	UserPresenceEditor?: ComponentType | null
}

这些字段的值类型是 ComponentType<...> | null每一项都可以被替换成自定义 React 组件,或被赋值为 null 从界面中整体移除。二者正是 tldraw UI 定制的一体两面——本文聚焦“移除(置 null)”这一面,而“替换”能力意味着你随时可在原位置放入自己的实现。

TldrawUiComponentsProvider(同一文件)为每个插槽提供了默认实现(DefaultToolbarDefaultContextMenuDefaultToasts……),随后用 ..._overrides 展开覆盖。你传入 components 的对象就是这份 override:命中的键覆盖默认实现或置空,未命中的键保留默认 UI。

此外,这些 UI 插槽与编辑内核的组件(如 ScribbleCanvasTLEditorComponents)共同组成了 <Tldraw> 上的 components prop,完整定义见 packages/tldraw/src/lib/Tldraw.tsxTLComponents extends TLEditorComponents, TLUiComponents {}

精确隐藏:将插槽置为 null

tldraw 官方示例 ui-components-hidden/README.md 的结论非常直接:

Hide any built-in UI component by setting its slot to null.

也就是说,默认 UI 的每一部分都是一个插槽,给该插槽传 null 即可将它从界面上移除。

完整示例:一口气隐藏全部内置 UI

示例实现见 UiComponentsHiddenExample.tsx。它使用 Required<TLUiComponents> 把每个插槽都显式置为 null,其价值首先是一份权威的“全部插槽清单”参考

import { TLUiComponents, Tldraw } from 'tldraw'
import 'tldraw/tldraw.css'

// [1]
const components: Required<TLUiComponents> = {
	ContextMenu: null,
	ActionsMenu: null,
	HelpMenu: null,
	ZoomMenu: null,
	MainMenu: null,
	Minimap: null,
	StylePanel: null,
	PageMenu: null,
	NavigationPanel: null,
	Toolbar: null,
	KeyboardShortcutsDialog: null,
	QuickActions: null,
	HelperButtons: null,
	DebugPanel: null,
	DebugMenu: null,
	SharePanel: null,
	MenuPanel: null,
	TopPanel: null,
	CursorChatBubble: null,
	RichTextToolbar: null,
	ImageToolbar: null,
	VideoToolbar: null,
	Dialogs: null,
	Toasts: null,
	A11y: null,
	FollowingIndicator: null,
	PeopleMenu: null,
	PeopleMenuAvatar: null,
	PeopleMenuItem: null,
	PeopleMenuFacePile: null,
	UserPresenceEditor: null,
}

export default function UiComponentsHiddenExample() {
	return (
		<div className="tldraw__editor">
			<Tldraw components={components} />
		</div>
	)
}

示例注释特别强调:

Setting a slot to null removes that part of the UI. Set only the slots you want to hide; the Required<> type is here so this example lists every slot, which is handy as a reference.

即示例代码刻意用 Required<> 列出全部插槽,是为了充当参考索引;实际业务中你只需要置空真正想去掉的那几个插槽,不要照抄全量清单。

按槽位类型逐一解读

结合 components.tsx 的类型定义,这 31 个插槽可归为几类,便于按需选择:

类别 插槽 说明
顶部菜单区 MenuPanelMainMenuHelpMenuZoomMenuActionsMenu 左上主菜单、帮助、缩放菜单与顶部动作菜单,MenuPanel 是装载它们的顶栏容器
核心画布工具 ToolbarQuickActionsHelperButtonsStylePanelRichTextToolbarImageToolbarVideoToolbar 左侧工具条、快捷操作、辅助按钮、右侧样式面板,以及选中文本/图片/视频时浮出的上下文工具条
导航与页面 MinimapNavigationPanelPageMenuContextMenu 右下小地图、页面导航面板、页面菜单与画布右键菜单
多人在线(协作) SharePanelPeopleMenuPeopleMenuAvatarPeopleMenuItemPeopleMenuFacePileCursorChatBubbleFollowingIndicatorUserPresenceEditor 分享面板、协作者头像菜单/头像列表/人脸堆叠、光标聊天气泡、跟随指示器与用户在场编辑。注意默认情况下 SharePanelCursorChatBubble 仅在协作 UI 开启时才显示(见 components.tsxshowCollaborationUi ? DefaultSharePanel : null 的写法)
弹层与对话框 DialogsToastsKeyboardShortcutsDialogDebugMenuDebugPanel 对话框宿主、Toast 宿主、快捷键对话框、调试菜单与底部调试面板
其他 TopPanelA11y 顶部通栏与无障碍播报。TopPanel 默认即为 null,只有需要顶部区域时才自定义

隐藏弹层/Toast/无障碍系统时的连带效应

README 给出一个重要警告:

Hiding Toasts, Dialogs, or A11y also disables the features that render through them.

这三者不是“纯外观”插槽,而是功能管道

  • Toasts 置为 null:Toast 宿主不再挂载,编辑器内部通过 toast 系统发出的通知将无处渲染,相关用户提示全部不可见;
  • Dialogs 置为 null:所有对话框失去宿主,典型的如「按 ? 打开的键盘快捷键面板」等弹窗流程都会随之失效;
  • A11y 置为 null:默认的无障碍(screen reader)播报器被移除,编辑器的实时状态播报关闭。

所以在定制时务必判断:你是只想“看不见”,还是连“背后的功能通路”一起关掉。如果只是想移走视觉元素而保留底层交互,应优先考虑把相关入口(菜单项、按钮)一并从 UI 中删除,而不是直接干掉 Toasts/Dialogs 宿主——官方 README 的表述明确提示了这两者的差异。

一键隐藏全部 UI:hideUi prop

如果你想要一个“只剩画布”的精简编辑器——保留画布、默认图形、全部工具与快捷键,但完全不渲染任何内置 UI——tldraw 提供了比逐项置空更直接的方式:<Tldraw hideUi />

配套示例见 hide-ui/README.mdHideUiExample.tsx

import { Tldraw } from 'tldraw'
import 'tldraw/tldraw.css'

export default function HideUiExample() {
	return (
		<div className="tldraw__editor">
			<Tldraw persistenceKey="hide-ui-example" hideUi />
		</div>
	)
}

其底层实现位于 packages/tldraw/src/lib/ui/TldrawUi.tsxhideUi 是 UI 组件的布尔属性,组件内部通过条件渲染阻止整个 UI 内容挂载。同时 Tldraw 组件在组合“画布之上”的图层时也做了联动判断——见 Tldraw.tsx:当 hideUi 为真时,不会再包一层默认 UI 外壳。换言之,hideUi 不是“把 31 个槽位逐个置空”,而是从 UI 渲染树的根部整体跳过,彻底性优于手动清空清单。

components 置空的差异点值得记住:

  • components 逐项置 null:适合保留 UI 整体结构、只去掉个别部件Toasts/Dialogs/A11y 被置空时还会顺带关闭背后的功能管道;
  • hideUi:适合完全无内置 UI 的嵌入场景(编辑器内核 + 你自己写的整套控制层)。行为正如官方注释所述——“removes all of tldraw's default UI but keeps the editor, its tools, and its keyboard shortcuts”。

实践建议:隐藏之后如何提供替代控制

无论用哪种方式,隐藏 UI 都不会禁用编辑器能力:

  • 快捷键仍然有效hide-ui 示例提示可以按 d 切换到画笔(draw)、按 r 插入矩形,因为工具切换走的是键盘快捷键系统,与 UI 渲染解耦;
  • 自建控制面板:在 <Tldraw> 内部渲染自组件,用 useEditor() hook 获取编辑器实例并调用 editor.setCurrentTool('draw')editor.getSelectedShapes() 等方法即可搭建自己的工具条/属性面板。官方推荐的起点是 custom-ui 示例(hide-ui 的 README 中也明确指引 “See the custom UI example for building your own controls”);
  • 按产品形态组合:需要“原生手感但去掉小地图/分享菜单”的,用 components 精准置空个别槽位;要做“白板内核 + 完全自定义外壳”(如笔记应用、设计工具内嵌画布)的,用 hideUi + useEditor() 自建控制层。

小结

从官方示例 ui-components-hidden 出发,tldraw 的 UI 隐藏体系可以总结为两条互补路径:

  1. 精确裁剪:把 TLUiComponents 中的任意插槽设为 null,按需移除单个 UI 部件;Required<TLUiComponents> 全量置空清单可作为插槽名速查表;同时留意 ToastsDialogsA11y 三个宿主插槽被移除时的功能连带关闭。
  2. 整体隐藏:传 hideUi prop,从渲染根部跳过整个默认 UI 外壳,得到保留画布、工具与快捷键的“裸”编辑器,再用 useEditor() 打造自己的控制层。

两种方案底层分别由 components.tsx 的插槽覆盖机制与 TldrawUi.tsxhideUi 条件渲染分支支撑,理解了这套机制,你就能在「全默认 UI」「混合定制 UI」「完全 headless」三种形态之间自由切换。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.81 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
920
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.79 K
1.02 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
390