组件
文字提示 Tooltip
在鼠标悬停或键盘聚焦时,为图标或紧凑控件浮层展示简短的上下文说明与快捷键。
基础用法
最基础的文字提示用法。包裹图标按钮,为纯图标交互提供明确的语义标签与快捷键说明:
Loading…
安装与引入
通过 CLI 自动添加组件,或手动复制源码至项目中:
pnpm dlx @wui-design/cli@latest add @wui/tooltip安装基础依赖与 Radix 原语
pnpm add radix-ui class-variance-authority clsx tailwind-merge复制组件源码到
components/ui/tooltip.tsx"use client"
import * as React from "react"
import { cva } from "class-variance-authority"
import { Tooltip as TooltipPrimitive } from "radix-ui"
import { cn } from "@/lib/utils"
const tooltipContentVariants = cva(
"z-50 max-w-72 origin-(--radix-tooltip-content-transform-origin) rounded-md bg-foreground font-medium text-background shadow-md outline-none will-change-[transform,opacity] animate-in fade-in-0 zoom-in-95 duration-150 ease-[cubic-bezier(0.22,1,0.36,1)] data-[side=bottom]:slide-in-from-top-1 data-[side=left]:slide-in-from-right-1 data-[side=right]:slide-in-from-left-1 data-[side=top]:slide-in-from-bottom-1 data-[state=instant-open]:zoom-in-100 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=closed]:duration-100 data-[state=closed]:ease-in motion-reduce:animate-none",
{
variants: {
size: {
sm: "px-2 py-1 text-[11px] leading-4",
default: "px-2.5 py-1.5 text-xs leading-4",
},
},
defaultVariants: {
size: "default",
},
}
)
export interface TooltipProviderProps
extends React.ComponentProps<typeof TooltipPrimitive.Provider> {}
/** Coordinates open delays between multiple tooltips. */
function TooltipProvider({
delayDuration = 350,
skipDelayDuration = 200,
...props
}: TooltipProviderProps) {
return (
<TooltipPrimitive.Provider
delayDuration={delayDuration}
skipDelayDuration={skipDelayDuration}
{...props}
/>
)
}
export interface TooltipProps
extends Omit<
React.ComponentProps<typeof TooltipPrimitive.Root>,
| "open"
| "defaultOpen"
| "onOpenChange"
| "delayDuration"
| "disableHoverableContent"
> {
/** Controlled open state. */
open?: boolean
/** Initial open state when uncontrolled. @default false */
defaultOpen?: boolean
/** Called whenever the open state changes. */
onOpenChange?: (open: boolean) => void
/** Hover delay in milliseconds for this tooltip. */
delayDuration?: number
/** Close when the pointer leaves the trigger instead of allowing content hover. @default false */
disableHoverableContent?: boolean
}
/** Controls the open state of one tooltip. */
function Tooltip(props: TooltipProps) {
return <TooltipPrimitive.Root {...props} />
}
function TooltipTrigger(
props: React.ComponentProps<typeof TooltipPrimitive.Trigger>
) {
return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />
}
export interface TooltipContentProps
extends Omit<
React.ComponentProps<typeof TooltipPrimitive.Content>,
"sideOffset"
> {
/** Physical size of the tooltip panel. @default "default" */
size?: "sm" | "default"
/** Gap in pixels between the trigger and panel. @default 6 */
sideOffset?: number
/** Whether to render the directional arrow. @default true */
showArrow?: boolean
}
/** A portal-rendered label or short description for the trigger. */
function TooltipContent({
className,
sideOffset = 6,
size = "default",
showArrow = true,
children,
...props
}: TooltipContentProps) {
return (
<TooltipPrimitive.Portal>
<TooltipPrimitive.Content
data-slot="tooltip-content"
data-size={size}
sideOffset={sideOffset}
className={cn(tooltipContentVariants({ size }), className)}
{...props}
>
{children}
{showArrow ? (
<TooltipPrimitive.Arrow
data-slot="tooltip-arrow"
className="fill-foreground"
width={8}
height={4}
/>
) : null}
</TooltipPrimitive.Content>
</TooltipPrimitive.Portal>
)
}
export {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
tooltipContentVariants,
}
属性 Props
TooltipProvider
用于全局或局部协调多个相邻 Tooltip 的打开与跳过延迟:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| delayDuration | number | 350 | 指针悬停到触发器后,浮层延迟显示的毫秒数。 |
| skipDelayDuration | number | 200 | 在移动到下一个相邻 Tooltip 时,跳过延迟直接显示的毫秒窗口期。 |
| disableHoverableContent | boolean | false | 当指针离开触发器时是否立即关闭提示(禁止指针移入 Tooltip 内容本身)。 |
Tooltip
单个提示项的根状态控制器:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| open | boolean | — | 受控模式下的展开状态。 |
| defaultOpen | boolean | false | 非受控模式下的初始展开状态。 |
| onOpenChange | (open: boolean) => void | — | 展开状态发生变化时的回调函数。 |
| delayDuration | number | — | 覆盖当前 Tooltip 单实例的悬停延迟毫秒数。 |
| disableHoverableContent | boolean | false | 单独对当前实例禁止悬浮内容检测。 |
TooltipTrigger
触发器组件,包裹触发 Tooltip 打开的目标元素:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| asChild | boolean | false | 是否将触发器属性与事件直接合并到传入的单个子元素上。 |
TooltipContent
浮层面板内容容器,挂载至 Portal 门禁并在视口边缘自动计算避让:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| size | "sm" | "default" | "default" | 提示面板的视觉尺寸。sm 为超紧凑微提示,default 为常规提示。 |
| side | "top" | "right" | "bottom" | "left" | "top" | 提示面板首选出现的方位。若视口空间不足会自动反转对齐。 |
| align | "start" | "center" | "end" | "center" | 提示面板在对应侧边缘的对齐方式。 |
| sideOffset | number | 6 | 提示面板与触发器之间的间距偏移量(像素)。 |
| showArrow | boolean | true | 是否在提示面板边缘渲染指向触发器的三角形指示箭头。 |
| className | string | — | 应用于提示面板容器的额外 CSS 类名。 |
事件 Events
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| onOpenChange | (open: boolean) => void | — | 提示因鼠标悬停、焦点获入/丢失或按键操作改变显隐状态时触发。 |
| onEscapeKeyDown | (event: KeyboardEvent) => void | — | 在 Tooltip 打开状态下按下 Escape 键时触发,可通过 event.preventDefault() 阻止关闭。 |
| onPointerDownOutside | (event: CustomEvent) => void | — | 在 Tooltip 范围外部发生指针按下事件时触发。 |
使用场景与设计规范
Tooltip 用于为界面中的紧凑元素(如纯图标按钮、截断缩略文本、专业术语指标)提供非必要、轻量级的辅助说明。
- 组件选型对比:
- Tooltip:只读纯文本或带快捷键的微提示,不可包含可交互链接或表单按钮。
- Popover:需要用户点击内部链接、复制大段文本或在浮层内填写简易表单时使用。
- Dialog / Modal:重大业务操作、复杂多步骤表单。
- 共享 TooltipProvider:建议在工具栏或页面根级使用单个
TooltipProvider,这样当用户快速从“复制”图标划到“剪切”图标时,第二个提示会瞬时响应而不会重复经历 350ms 的等待延迟。 - 文案克制原则:Tooltip 文案应极度精炼(通常 1~2 句话或若干词汇),避免大段冗长段落。
场景示例
弹出方位与指示箭头
支持 top、right、bottom、left 四个方向定位,并内置智能防溢出碰撞检测。提示从触发器方向轻微滑入,并以箭头所在位置为缩放原点展开:
Loading…
尺寸规格与快捷键徽标
提供 default 与 sm 尺寸,并在内容中以弱化文字标注键盘快捷键。在同一个 TooltipProvider 内快速划过多个触发器时,后续提示瞬时切换,仅保留淡入而不再缩放:
Loading…
丰富上下文说明(多行/状态说明)
在需要辅助解释复杂系统安全机制或指标含义时使用富文本样式:
Loading…
受控模式
通过 open 与 onOpenChange 将提示显隐状态委托给外部 React 状态。示例中点击复制后主动展开“已复制”反馈,并在提示期间忽略指针移出导致的关闭:
Loading…
无障碍与交互 Accessibility
- ARIA 关联规范:底层自动为触发器赋予
aria-describedby关联 TooltipContent 的唯一 ID,屏幕阅读器在聚焦时能即刻播报提示内容。 - 键盘焦点感知:当用户使用 Tab 键将焦点导航至触发器时,Tooltip 会自动展开;按下 Esc 键可立即关闭提示。
- 视口边缘碰撞避让:内置智能碰撞检测(Collision Detection),当触发器靠近屏幕边缘导致 Tooltip 放不下时,浮层会自动翻转至对立侧或调整轴向偏移。
- 触控设备优化:在移动端长按触发器时能呼出提示,松手后轻触外部任意区域即可平滑收起。
- 动效降级:进入与退出动画在系统开启“减少动态效果”时自动关闭。