跳到主要内容

文字提示

Tooltip 在悬停或键盘聚焦时为控件命名或补充一句纯文本提示,支持快捷键展示、触摸开合与多触发器共享。

Tooltip(文字提示)在指针停留或键盘聚焦到达时,为控件命名或补充一句简短提示,保持几个词的纯文本即可。需要交互的内容用弹出框,链接目标的预览用悬停卡片。

演示

悬停或用 Tab 聚焦「B」「I」按钮,提示显示名称与快捷键;在同一工具栏内移动时,提示即时跟随而不重复等待延迟。

悬停或聚焦查看提示与快捷键

组合

Tooltip
├── TooltipTrigger
└── TooltipContent
    ├── TooltipArrow
    └── TooltipShortcut

箭头与快捷键可选。内容具有 tooltip 角色,从一开始就隐藏在页面中,因此焦点到达前就能为触发器命名或描述:没有自身名称的触发器(如纯图标按钮)被命名,其余被描述,type="label" / type="description" 可覆盖这个判断。提示不可聚焦,里面放链接或按钮无法到达,交互内容请改用弹出框或悬停卡片。

用法

import { Tooltip, TooltipContent, TooltipTrigger } from "@ui-sdk/react/tooltip";

function Example() {
  return (
    <Tooltip>
      <TooltipTrigger>分享</TooltipTrigger>
      <TooltipContent>任何拥有链接的人都可以查看</TooltipContent>
    </Tooltip>
  );
}

快捷键提示

根部件的 shortcut(如 "mod+s")只是提示触发器动作绑定的按键,mod 在 Apple 平台是 Command,其余是 Control。TooltipShortcut 按平台显示 ⌘S 或 Ctrl+S,对屏幕阅读器隐藏;触发器获得 aria-keyshortcuts 让读屏用户听到。它也可以用自己的 shortcut 显示其他按键。

提示本身不绑定按键:用 @ui-sdk/core/shortcuts 的 registerShortcut 自行注册,或使用会绑定按键的组件(如对话框触发器的 shortcut)。

<Tooltip shortcut="mod+s">
  <TooltipTrigger aria-label="保存">
    <SaveIcon aria-hidden="true" />
  </TooltipTrigger>
  <TooltipContent>
    保存
    <TooltipShortcut />
  </TooltipContent>
</Tooltip>

触摸与按下行为

触摸屏没有悬停,点按普通提示的触发器只会执行按钮本身,提示保持关闭,所以不要把重要信息藏进提示。只为提示而存在的信息按钮加 toggleable:按下即开合,手指、鼠标、键盘都有效,按下打开时播报文本,外部点击或 Escape 也能关闭。

按下触发器默认关闭提示(closeOnPress),以免盖住按下后变化的内容,并在指针离开前保持关闭;设为 false 可保持打开,例如提示变成「已复制」的复制按钮。原生 disabled 按钮无法聚焦、部分浏览器不派发指针事件,提示永远不显示:要解释原因为何不可用时,改用 aria-disabled="true" 并自行忽略按下,按钮恢复可用后用提示的 disabled 关掉解释。

<Tooltip toggleable>
  <TooltipTrigger aria-label="关于存储空间">
    <InfoIcon aria-hidden="true" />
  </TooltipTrigger>
  <TooltipContent>回收站中的文件仍占用空间。</TooltipContent>
</Tooltip>

延迟与分组

delay 是指针停留多久后打开,默认 600 毫秒;closeDelay 是指针离开触发器与提示后多久关闭,默认 0;键盘聚焦立即打开。提示无需 provider 自动分组:一个打开着或刚关闭不久时,悬停下一个立即打开,且同一时刻只有一个打开,沿工具栏移动就像一条跟着指针的提示;立即打开的提示带 data-instant,可跳过动画。disabled 阻止打开,触发器照常工作。

<Tooltip delay={300} closeDelay={150} disabled={!showHints}>

多触发器共享一个提示

工具栏、图表或长列表可以共享一条提示:把触发器与提示连到同一个 createTooltipController<Payload>(),触发器可以在页面任何位置,各自传 payload,内容从 state.payload 读取(首次打开前就会渲染,要处理 undefined)。只有打开提示的触发器被它描述,所以每个触发器要有自己的名称(如 aria-label)。controller.open({ payload, anchor }) 可从代码打开(例如引导教程的一步),onPayloadChange 报告每次载荷变化。

const tip = createTooltipController<string>();

<TooltipTrigger controller={tip} payload="加粗" aria-label="加粗">
  <BoldIcon aria-hidden="true" />
</TooltipTrigger>

<Tooltip controller={tip}>
  <TooltipContent<string>>{(state) => state.payload}</TooltipContent>
</Tooltip>

样式与状态

内容默认在触发器上方(side="top"),空间不足时翻转并平移保持可见;sideOffset 默认 4px,align、alignOffset、collisionPadding、arrowPadding 与 anchor(元素、选择器、{ x, y } 点)和弹出框一致。TooltipArrow 跟随实际落点一侧。

data-slot 为 tooltip-content 与 tooltip-arrow,带 data-open / data-closed、data-side / data-align,内容另有 data-starting-style / data-ending-style 与 data-instant;触发器与 Shortcut 没有状态属性,因为触发器常兼任其他组件的触发器。CSS 变量:--anchor-width / --anchor-height、--available-width / --available-height、--transform-origin、--arrow-offset。

[data-slot="tooltip-content"] {
  transform-origin: var(--transform-origin);
  transition: opacity 150ms ease-out, scale 150ms ease-out;
}
[data-slot="tooltip-content"]:is([data-starting-style], [data-ending-style]) {
  opacity: 0;
  scale: 0.9;
}
[data-slot="tooltip-content"][data-instant] {
  transition: none;
}

提示就地渲染进浏览器顶层,不会被祖先裁剪或遮盖,container 可移动 DOM;退场播完才卸载,onOpenChangeComplete 在动画结束后触发。详见弹出层。

API

Prop 类型 说明
open / defaultOpen boolean 受控 / 非受控的开合状态。
onOpenChange (open, details) => void 开合变更;details.reason 如 trigger-hover、trigger-focus、escape-key,可 cancel()。
onOpenChangeComplete (open: boolean) => void 动画结束后报告开合完成。
onPayloadChange (payload, details) => void 共享提示的载荷变化,可 cancel()。
delay / closeDelay number 打开 / 关闭前的停顿,默认 600ms / 0ms。
disabled boolean 不打开提示,触发器照常工作。
toggleable boolean 按下触发器开合提示,供触摸与信息按钮使用。
closeOnPress boolean 按下触发器是否关闭提示,默认 true。
type "label" | "description" 覆盖命名 / 描述的自动判断。
shortcut string 快捷键提示,不绑定按键。
controller PopupController 用 createTooltipController() 创建,连接外部触发器。
container Element | DocumentFragment | null 渲染到指定元素而非就地。

TooltipContent 另有 side、align、sideOffset、alignOffset、collisionPadding、arrowPadding、anchor、container;TooltipTrigger 有 payload 与 controller;TooltipShortcut 有 shortcut。

键盘与无障碍

触发器由提示命名或描述,遵循 WAI-ARIA tooltip 模式;悬停与键盘聚焦都会打开,指针移到提示上不会关闭。

按键 行为
Tab 聚焦触发器立即打开;焦点离开即关闭
Escape 关闭提示,焦点留在触发器,不关闭外层的对话框或菜单
Enter / Space 按下触发器并关闭提示;toggleable 时开合提示

提示内容不可聚焦,也不应包含交互元素。只在文本被截断时显示提示,可在 onOpenChange 里比较 scrollWidth 与 clientWidth,放得下就 details.cancel(),并用 type="label" 避免读屏重复朗读。

相关组件

  • 弹出框:点击打开、可交互的内容。
  • 悬停卡片:链接目标的丰富预览。
  • 弹出层:顶层渲染与定位变量的共享模型。
  • 控制器:多触发器共享一条提示的连接方式。

输入关键词搜索…

↑↓ 移动↵ 选择Esc 关闭