Tooltip 文字提示
悬停或聚焦时出现的一句纯文字说明。
用法
悬停或聚焦触发器即显示;指针停在提示上也不收起
组件结构
加粗的是必需部件。
data-scope="tooltip":trigger · positioner · content · text · shortcut · arrow
示例
朝向
placement 是请求值,空间不足时由定位引擎避让;箭头跟随最终落定的一面
延时
openDelay 默认 150ms 用于防误触,closeDelay 默认 100ms 留出指针移动的余地;聚焦不经这两段等待
禁用
disabled 只关闭提示本身,被包裹的触发器照常可点击、可聚焦
颜色
六种语气更换浮层实心底与其上的文字色,箭头一并随之变化;把指针停在触发器上(或用 Tab 聚焦)查看差别
尺寸
三档改变浮层的内边距与字号,不写 size 即默认档;把指针停在触发器上(或用 Tab 聚焦)查看差别
受控
传入 open 后由宿主决定;悬停、聚焦、Escape 都只发意图,最终是否写回由外部的这份状态决定
长文案
提示到达宽度上限后换行,不会拉成一条横线;上限是 content 上的 --xh-tooltip-max-w 槽位
提示组
XhTooltipProvider 把一排提示放进同一组:没写延时的取组的缺省,组里另一个开着时指向下一个直接接替,同一时刻只开一个
跟随鼠标
followCursor 让提示锚在指针落点上并随移动更新;触屏与键盘聚焦时仍锚在触发器上
委托
delegate 让一个提示管一整排按钮:文字取按钮的 data-xh-tooltip 或可及名,快捷键取 aria-keyshortcuts;指针在按钮之间挪动时提示直接换过去
设计指引
何时使用
- 补充说明图标按钮的含义,或截断文字的全文。
- 内容是纯文字,且没有任何可交互元素。
何时不用
- 内容中有按钮或链接时,使用气泡卡片,提示无法交互。
- 信息重要到不能错过时,写在界面上,不放进悬停。
- 触摸设备是主要场景时,没有悬停。
特性
openDelay/closeDelay防止指针经过时连续闪烁。- 同页的提示共用一个接替窗口(
skipDelayDuration,默认 300ms):另一个提示还开着、或刚收起一个不到这么久时,指向下一个不再等openDelay、也不播进场,直接接替,上一个随之收起。横扫一排工具栏钮时提示一个个跟上。 XhTooltipProvider(Web Components 为<xh-tooltip-provider>容器元素)把子树里的提示放进同一组:组内共用接替窗口、同一时刻只开一个,不同组之间互不接替、互不收起;组上的openDelay/closeDelay/skipDelayDuration是组内提示的缺省,提示自己写了就以提示为准。没放进 Provider 的提示同属页面级的那一组。Provider 自身不渲染节点,Web Components 那个元素是display: contents。followCursor让由指针打开的提示锚在指针落点上,指针在触发器上挪动时跟过去;触屏没有悬停落点、键盘聚焦没有指针,这两种情形仍锚在触发器上。跟随中的浮层不接指针,免得挡住触发器上的移动;位置跟手,不做过渡。delegate让一个提示管一整个容器,一条工具栏不必每个按钮各包一个提示:- 值是 CSS 选择器。trigger 此时是容器,皮肤让它不占盒子;容器里命中选择器的元素就是一个个锚点。
- 悬停或键盘聚焦到锚点时打开,提示锚在这个元素上;指针或焦点挪到另一个锚点时直接换过去,不再等延时、也不重播进场。
- 指针移出容器、焦点离开容器或按 Esc 时收起;按下仍让位给真正的操作,随按下而来的聚焦不打开。
- 文字取锚点的
data-xh-tooltip,没写时取锚点的可及名;快捷键取锚点的aria-keyshortcuts(规范写法,如Control+Shift+Z),按platform写成 ⌘⇧Z 或 Ctrl+Shift+Z。两者铺在 content 里的text与shortcut部件里,排在作者写的箭头之后。 - 提示文字与锚点的名字不同(写了
data-xh-tooltip)时,锚点的aria-describedby引用text;相同就不引用,读屏不念两遍。快捷键只由锚点自己的aria-keyshortcuts报给读屏。 - 原生禁用的按钮仍收得到指针事件,悬停照样出提示;键盘本来就停不到它。
- 聚焦也能触发,键盘用户可以访问。
- 按下触发器即收起,让位给真正的操作;点击带来的那次聚焦不再把提示打开,指针移开再回来、或用键盘聚焦时照常出现。
- 语气与尺寸两轴。
- 默认与 Popover 同一副浮层面(compact 档 frosted):底、字、边取 frosted 材质,两个主题都不反白,与 Popover 靠一行字的尺寸与控件圆角区分。写了
tone换实心语气底配不透明文字,边界由 on 色 20% 的拼色描边承担(中性描边压在彩色底上看不见),这时面内成为墨色域。箭头和气泡同色同边,不画顶部高光;圆角取控件档。 - 正文 14px;内距缺省纵 8 横 12,
sm只收纵向(纵 4 横 12),lg纵 12 横 16,三档字号不变。 - 进退场走弹层那一套(
xh-overlay-pop-in/xh-pop-out):从锚点一侧短移、淡入放大,退场缩小淡出;入场--xh-motion-duration-enter(200ms),退场--xh-motion-duration-exit(150ms),与其他锚定列表浮层同一节奏。
组合
最佳实践
- 一句话说完,超过一行应换其他形式。
- 必须显示较长的单句时让它在最大宽度内换行;连续长词也会断行,不会把浮层撑出窄屏。
- 图标按钮的可访问名称写在按钮上(
aria-label),提示只是视觉补充。
当前边界
- 触发器滚动关闭仍是后续独立行为功能。
- 共享浮层位移原语当前最小档是 4px;Tooltip 与其余弹层使用同一
xh-overlay-pop-in/xh-pop-out定义。规格中的 2px 需要新增公共 motion distance 档后统一接入,不能局部改写现有语义令牌。
反模式
- 把唯一的操作说明放进提示,触摸用户无法看到。
- 提示内放链接。
API 参考
产物
| 层 | 值 |
|---|---|
| 自定义元素 | <xh-tooltip> |
| Vue 组件 | XhTooltipArrow XhTooltipContent XhTooltipPositioner XhTooltipProvider XhTooltipRoot XhTooltipShortcut XhTooltipText XhTooltipTrigger |
| 组合式函数 | useTooltip |
| 状态机 | tooltipMachine |
| 皮肤 | @xihan-ui/styles/tooltip.css |
Props
| 属性 | 类型 | 必填 | 说明 |
|---|---|---|---|
open | boolean | ||
defaultOpen | boolean | ||
placement | Placement | 请求的浮层朝向,默认 bottom;空间不足时由定位引擎避让。 | |
dir | Direction | 文字方向,默认 ltr。只改写浮层在行内轴上 start 与 end 的落点。 | |
offset | number | 浮层与锚点的间距(px)。 | |
openDelay | number | 悬停进入到展开的等待毫秒,默认 150。 | |
closeDelay | number | 悬停移出到收起的等待毫秒,默认 100。 | |
skipDelayDuration | number | 跳过等待的窗口毫秒,默认 300:另一个提示还开着,或刚收起一个不到这么久时,指向这一个不等 openDelay、 也不播进场,直接接替(上一个随之收起)。0 或负数表示不参与接替,每次都等 openDelay。 | |
disabled | boolean | 只关闭提示本身,不影响被包裹控件的可用性。 | |
followCursor | boolean | 跟随鼠标:由指针打开的提示锚在指针落点上,随指针在 trigger 上移动而更新,默认 false。 触屏没有悬停落点、聚焦打开没有指针,这两种情形退回锚定到 trigger。 | |
delegate | string | 委托模式:值是一个 CSS 选择器。trigger 此时是容器,容器里命中选择器的元素在悬停或键盘聚焦时打开提示, 提示锚在这个元素上;指针或焦点挪到另一个锚点时提示直接换过去。文字取锚点的 data-xh-tooltip, 没写时取锚点的可及名;快捷键取锚点的 aria-keyshortcuts。 | |
platform | KbdPlatform | 委托模式下快捷键按哪个平台的写法显示:auto(缺省)在指向锚点时测一次。 | |
tone | Tone | 语气:brand / neutral / success / warning / danger / info,决定提示的底色与其上的文字色。 | |
size | Size | 尺寸:sm / md / lg,决定内边距与字号档位。 | |
translations | Partial<TooltipTranslations> | ||
onOpenChange | (details: TooltipOpenChangeDetails) => void | open 变化意图回调;受控时是唯一出口,非受控时随内部转移一并通知。 |
事件
自定义元素将载荷放在 detail;Vue 使用同名 emit。
| 事件 | 载荷 | 说明 |
|---|---|---|
open-change | TooltipOpenChangeDetails | open 状态变化;detail 为 { open: boolean } |
插槽
仅列出带载荷的插槽。
| Vue 组件 | 插槽 | 载荷 | 说明 |
|---|---|---|---|
XhTooltipRoot | default | TooltipRootSlotProps |
React 适配器 props
只列各组件自己声明的那些:继承自 ComponentPropsWithRef 的 DOM 属性不在其中,根组件上与上面 Props 表同名的也不重复列。Vue 的对应物是上面的插槽表。
| React 组件 | 属性 | 类型 | 必填 | 说明 |
|---|---|---|---|---|
XhTooltipPositioner | container | () => Element | null | 浮层挂载的容器;未提供时按全局配置,再未提供时挂载到 body。 | |
XhTooltipProvider | openDelay | number | 组内提示悬停进入到展开的缺省等待毫秒;提示自己写了就以提示为准。 | |
XhTooltipProvider | closeDelay | number | 组内提示悬停移出到收起的缺省等待毫秒。 | |
XhTooltipProvider | skipDelayDuration | number | 组内提示的缺省接替窗口毫秒;0 表示组内不接替。 | |
XhTooltipProvider | children | ReactNode | ||
XhTooltipRoot | children | SlotChildren<TooltipRootSlotProps> |
状态
公开状态写入 data-state。
| 部件 | 取值 |
|---|---|
trigger | 'open' | 'closed' |
positioner | 'open' | 'closed' |
content | 'open' | 'closed' |
以下名称仅用于内部状态机。
状态:closed · opening · visible · visible.open · visible.closing
事件:POINTER.ENTER · POINTER.MOVE · POINTER.LEAVE · POINTER.DOWN · FOCUS · BLUR · ESCAPE · OPEN · CLOSE · after.openDelay · after.closeDelay · CONTROLLED.OPEN · CONTROLLED.CLOSE
判据:isOpenControlled · isDisabled · isFocusOpened · hasAnchor
connect API
getXxxProps() 返回对应部件的宿主属性。
| 成员 | 类型 | 说明 |
|---|---|---|
open | boolean | |
setOpen | (next: boolean) => void | |
delegated | boolean | 委托模式:trigger 是容器,content 里由组件铺 text 与 shortcut。 |
text | string | 委托模式下当前锚点的提示文字;还没有锚点时为空串。 |
shortcut | string | null | 当前锚点的快捷键,按平台写成一串字(⌘⇧Z、Ctrl+Shift+Z);没有时为 null。 |
getTriggerProps | () => T['button'] | |
getPositionerProps | () => T['element'] | |
getContentProps | () => T['element'] | |
getArrowProps | () => T['element'] | |
getTextProps | () => T['element'] | |
getShortcutProps | () => T['element'] |
无障碍
键盘
规格出处:W3C APG
| 按键 | 生效条件 | 行为 |
|---|---|---|
Tab / Shift+Tab | not disabled | 焦点进入 trigger 立即展开、离开立即收起,都不走延时 |
Escape | 展开中且本层在层栈栈顶,或 focus in trigger 且等待展开中 | 立即收起,不等 closeDelay;下层浮层不受这一次按键影响 |
ARIA
以下属性由 connect 生成。
| 部件 | 属性 | 值 |
|---|---|---|
trigger | aria-describedby | content 部件的 id | undefined |
content | aria-hidden | !open || undefined |
content | role | 'tooltip' |
shortcut | aria-hidden | 'true' |
arrow | aria-hidden | 'true' |
样式参考
皮肤
@xihan-ui/styles/tooltip.css 按 [data-scope="tooltip"][data-part="trigger"] 部件选择器书写,发布产物以挂载类 .xh-scope-tooltip 代替其中的 data-scope(特异性相同),位于 xihan.components 层。覆盖样式使用 xihan.overrides,部件选择器照常可用。
forced-colors: active 下另有一套规则:颜色交给系统,边框与状态标记改用系统色关键字。
数据属性
由 connect 生成;条件不成立时不输出无值属性。
| 部件 | 属性 | 值 |
|---|---|---|
trigger | data-delegate | '' |
trigger | data-disabled | ''(条件成立时才出现) |
trigger | data-state | 'open' | 'closed' |
positioner | data-follow-cursor | ''(条件成立时才出现) |
positioner | data-hidden | ''(条件成立时才出现) |
positioner | data-placement | 定位引擎算出的实际落位 |
positioner | data-positioned | ''(条件成立时才出现) |
positioner | data-state | 'open' | 'closed' |
content | data-instant | ''(条件成立时才出现) |
content | data-size | props.size |
content | data-state | 'open' | 'closed' |
content | data-tone | props.tone |
content | data-xh-ink-surface | ''(条件成立时才出现) |
arrow | data-placement | 定位引擎算出的实际落位 |
CSS 变量
本组件公开覆盖槽由独立皮肤的实际消费位生成;默认来源、作用部件和状态均与 CSS 同源。
| 变量 | 部件 | CSS 属性 | 状态 | 默认来源 | 说明 |
|---|---|---|---|---|---|
--xh-tooltip-arrow-size | arrow | --xh-_overlay-arrow-size | default | --xh-overlay-arrow-size | tooltip 的 arrow 部件 --xh-_overlay-arrow-size 覆盖槽。 |
--xh-tooltip-backdrop | content | -webkit-backdrop-filterbackdrop-filter | default | --xh-material-frosted-compact-backdrop | tooltip 的 content 部件 -webkit-backdrop-filter、backdrop-filter 覆盖槽。 |
--xh-tooltip-bg | arrowcontent | --xh-ink-surfacebackground | defaultxh-ink-surface | --xh-_tooltip-solid | tooltip 的 arrow、content 部件 --xh-ink-surface、background 覆盖槽。 |
--xh-tooltip-border | arrowcontent | border | default | --xh-_tooltip-border | tooltip 的 arrow、content 部件 border 覆盖槽。 |
--xh-tooltip-fg | content | color | default | --xh-_tooltip-on | tooltip 的 content 部件 color 覆盖槽。 |
--xh-tooltip-font-size | content | font-size | default | --xh-_tooltip-font-size | tooltip 的 content 部件 font-size 覆盖槽。 |
--xh-tooltip-highlight | content | box-shadow | default | transparent | tooltip 的 content 部件 box-shadow 覆盖槽。 |
--xh-tooltip-layer | positioner | z-index | default | --xh-_layer | tooltip 的 positioner 部件 z-index 覆盖槽。 |
--xh-tooltip-max-w | content | max-inline-size | default | --xh-overlay-max-w | tooltip 的 content 部件 max-inline-size 覆盖槽。 |
--xh-tooltip-px | content | padding-inline | default | --xh-_tooltip-px | tooltip 的 content 部件 padding-inline 覆盖槽。 |
--xh-tooltip-py | content | padding-block | default | --xh-_tooltip-py | tooltip 的 content 部件 padding-block 覆盖槽。 |
--xh-tooltip-radius | content | border-radius | default | --xh-shape-control | tooltip 的 content 部件 border-radius 覆盖槽。 |
--xh-tooltip-shadow | content | box-shadow | default | --xh-material-frosted-compact-shadow | tooltip 的 content 部件 box-shadow 覆盖槽。 |
--xh-tooltip-trigger-gap | trigger | gap | default | --xh-control-gap-sm | tooltip 的 trigger 部件 gap 覆盖槽。 |
动效
动效角色:出现(见动效规范)。
共享关键帧 xh-overlay-pop-in · xh-pop-out 由 family/motion.css 提供,皮肤 @import 它,单独引入仍成立。时长与缓动读动效令牌,改令牌即改全局节奏。
皮肤之外还有一段:退场由适配器的退场闸门把关,动画播完才真收起。
系统开启减弱动效时由令牌层统一收敛,皮肤不另作判断。
RTL
皮肤用逻辑属性排布(inline-start 一族),dir="rtl" 下自动镜像。
