unnamed-ui
基础

Tooltip

Tooltip component for displaying contextual information on hover or focus

"use client";

import { Tooltip } from "@/components/composed/tooltip/tooltip";
import { Button } from "@/components/ui/button";

/**
 * 基础 Tooltip 示例
 */
export function TooltipBasic() {
  return (
    <div className="flex items-center gap-4">
      <Tooltip content="这是一个提示信息">
        <Button variant="outline">悬停查看提示</Button>
      </Tooltip>

      <Tooltip content="点击按钮执行操作" side="bottom">
        <Button>操作按钮</Button>
      </Tooltip>
    </div>
  );
}

Tooltip 组件用于在用户悬停或聚焦元素时显示额外的上下文信息、帮助文本或操作说明,提供简化的 API 便于快速使用。

概述

  • 简化的 API:单个组件封装,无需手动组合多个子组件
  • 灵活定位:支持四个方向的定位(top, right, bottom, left)
  • 响应式宽度:最小宽度 36px,最大宽度 480px,自动适应内容
  • 深色背景:使用设计系统变量,确保样式一致性
  • 流畅动画:内置淡入淡出和缩放动画
  • 完整的可访问性:基于 Radix UI,支持键盘导航和屏幕阅读器

快速开始

import { Tooltip } from "@/registry/wuhan/composed/tooltip";

export function Example() {
  return (
    <Tooltip content="这是提示信息">
      <Button>悬停查看</Button>
    </Tooltip>
  );
}

特性

  • 快速集成:单个组件即可完成,无需额外配置
  • 自动换行:长文本自动换行,保持良好的可读性
  • 灵活定位:支持 4 个方向和 3 种对齐方式
  • 自定义样式:支持自定义类名和样式
  • 性能优化:延迟加载和按需渲染
  • 类型安全:完整的 TypeScript 类型定义

安装

pnpm dlx shadcn@latest add http://localhost:3000/r/wuhan/tooltip.json

代码演示

基本

基础用法,快速添加提示信息。

"use client";

import { Tooltip } from "@/components/composed/tooltip/tooltip";
import { Button } from "@/components/ui/button";

/**
 * 基础 Tooltip 示例
 */
export function TooltipBasic() {
  return (
    <div className="flex items-center gap-4">
      <Tooltip content="这是一个提示信息">
        <Button variant="outline">悬停查看提示</Button>
      </Tooltip>

      <Tooltip content="点击按钮执行操作" side="bottom">
        <Button>操作按钮</Button>
      </Tooltip>
    </div>
  );
}

不同位置

不同位置的提示框展示。

"use client";

import { Tooltip } from "@/components/composed/tooltip/tooltip";
import { Button } from "@/components/ui/button";

/**
 * 不同位置的 Tooltip 示例
 */
export function TooltipPositions() {
  return (
    <div className="flex items-center justify-center gap-4 flex-wrap">
      <Tooltip content="顶部提示信息" side="top">
        <Button variant="outline">顶部</Button>
      </Tooltip>

      <Tooltip content="右侧提示信息" side="right">
        <Button variant="outline">右侧</Button>
      </Tooltip>

      <Tooltip content="底部提示信息" side="bottom">
        <Button variant="outline">底部</Button>
      </Tooltip>

      <Tooltip content="左侧提示信息" side="left">
        <Button variant="outline">左侧</Button>
      </Tooltip>
    </div>
  );
}

配合图标

图标按钮配合 Tooltip 使用。

"use client";

import { Tooltip } from "@/components/composed/tooltip/tooltip";
import { Button } from "@/components/ui/button";
import { Info, HelpCircle, AlertCircle, Settings } from "lucide-react";

/**
 * 带图标的 Tooltip 示例
 */
export function TooltipWithIcons() {
  return (
    <div className="flex items-center gap-4">
      <Tooltip content="了解更多信息">
        <Button variant="ghost" size="icon">
          <Info className="w-4 h-4" />
        </Button>
      </Tooltip>

      <Tooltip content="获取帮助" side="bottom">
        <Button variant="ghost" size="icon">
          <HelpCircle className="w-4 h-4" />
        </Button>
      </Tooltip>

      <Tooltip content="重要提示" side="right">
        <Button variant="ghost" size="icon">
          <AlertCircle className="w-4 h-4" />
        </Button>
      </Tooltip>

      <Tooltip content="打开设置" side="left">
        <Button variant="ghost" size="icon">
          <Settings className="w-4 h-4" />
        </Button>
      </Tooltip>
    </div>
  );
}

长文本

长文本自动换行显示。

"use client";

import { Tooltip } from "@/components/composed/tooltip/tooltip";
import { Button } from "@/components/ui/button";

/**
 * 长文本 Tooltip 示例
 */
export function TooltipLongText() {
  return (
    <div className="flex items-center gap-4">
      <Tooltip
        content="这是一段比较长的提示文本,用于展示 Tooltip 组件如何处理较长的内容。组件会自动换行并保持适当的宽度。"
        side="top"
      >
        <Button variant="outline">查看长文本提示</Button>
      </Tooltip>

      <Tooltip
        content="Tooltip 最大宽度为 480px,超过这个宽度的内容会自动换行显示,确保内容的可读性和美观性。"
        side="bottom"
      >
        <Button variant="outline">底部长文本</Button>
      </Tooltip>
    </div>
  );
}

API

Tooltip

简化的 Tooltip 组件,封装了常用的配置和用法。

Props

PropTypeDefaultDescription
contentReact.ReactNode-提示内容(必填)
childrenReact.ReactNode-触发器元素(必填)
side"top" | "right" | "bottom" | "left""top"提示框位置
sideOffsetnumber4与触发器的距离(像素)
align"start" | "center" | "end""center"对齐方式
contentClassNamestring-自定义内容容器类名
delayDurationnumber0延迟显示时间(毫秒)

Example

import { Tooltip } from "@/registry/wuhan/composed/tooltip";
import { Button } from "@/components/ui/button";
import { Info } from "lucide-react";

function Example() {
  return (
    <div className="space-y-4">
      {/* 基础用法 */}
      <Tooltip content="这是提示信息">
        <Button>悬停查看</Button>
      </Tooltip>
      
      {/* 指定位置 */}
      <Tooltip content="右侧提示" side="right">
        <Button variant="outline">右侧提示</Button>
      </Tooltip>
      
      {/* 图标按钮 */}
      <Tooltip content="了解更多">
        <Button variant="ghost" size="icon">
          <Info className="w-4 h-4" />
        </Button>
      </Tooltip>
      
      {/* 长文本 */}
      <Tooltip 
        content="这是一段较长的提示文本,会自动换行显示"
        side="bottom"
      >
        <Button variant="outline">查看详情</Button>
      </Tooltip>
    </div>
  );
}

位置和对齐

Side(位置)

  • top - 显示在触发器上方(默认)
  • right - 显示在触发器右侧
  • bottom - 显示在触发器下方
  • left - 显示在触发器左侧

Align(对齐)

  • start - 与触发器起始边对齐
  • center - 与触发器中心对齐(默认)
  • end - 与触发器结束边对齐

使用场景

  • 图标按钮说明:为图标按钮提供文字说明
  • 表单字段帮助:在表单字段旁显示帮助信息
  • 功能介绍:介绍功能按钮或选项的作用
  • 状态说明:解释状态标签或指示器的含义
  • 操作提示:提示用户可以执行的操作
  • 数据展示:在表格或列表中显示完整信息

最佳实践

  1. 内容简洁:提示内容应简短明了,通常不超过 1-2 句话
  2. 及时响应:使用默认的 0ms 延迟,确保用户悬停时立即显示
  3. 位置选择:根据触发器位置和屏幕空间选择合适的方向
  4. 避免重复:不要在已有文字说明的元素上重复添加 Tooltip
  5. 键盘友好:确保触发器元素可以通过键盘访问
  6. 移动端考虑:移动端建议使用其他方式展示提示信息

注意事项

  • Tooltip 需要触发器元素支持 asChild 模式,建议使用 Button 或其他可交互元素
  • 长文本会自动换行,但建议控制在合理长度以保持可读性
  • 在移动设备上,Tooltip 可能不够友好,考虑使用替代方案
  • 避免在 Tooltip 中放置交互元素,因为内容在失去焦点时会关闭
  • 确保提示内容不会遮挡重要信息或操作按钮

原语组件

Tooltip 基于以下原语组件构建:

  • BlockTooltip - Tooltip 根组件
  • BlockTooltipTrigger - 触发器组件
  • BlockTooltipContent - 内容组件
  • BlockTooltipProvider - 提供者组件

原语组件提供了更底层的控制,可以在 registry/wuhan/blocks/tooltip/tooltip-01.tsx 中找到。

样式定制

组件使用 CSS 变量,可以通过以下方式定制:

// 自定义内容样式
<Tooltip 
  content="自定义样式"
  contentClassName="bg-primary text-primary-foreground"
>
  <Button>自定义</Button>
</Tooltip>

设计系统变量

  • 背景色--bg-mask(深色半透明背景)
  • 文本颜色--text-inverse(白色文本)
  • 字体--font-family-cn(中文字体)
  • 字号:12px
  • 行高--line-height-1
  • 圆角--radius-sm(4px)
  • 内边距:上下 --gap-xs(4px),左右 --gap-sm(6px)
  • 宽度范围:36px - 480px

扩展示例

Toolbar Integration

工具栏中集成多个 Tooltip。

"use client";

import { Tooltip } from "@/components/composed/tooltip/tooltip";
import { Button } from "@/components/ui/button";
import { Copy, Download, Share2, Trash2 } from "lucide-react";

/**
 * 工具栏 Tooltip 示例
 */
export function TooltipToolbar() {
  return (
    <div className="inline-flex items-center gap-1 p-2 border rounded-lg bg-background">
      <Tooltip content="复制">
        <Button variant="ghost" size="icon">
          <Copy className="w-4 h-4" />
        </Button>
      </Tooltip>

      <Tooltip content="下载">
        <Button variant="ghost" size="icon">
          <Download className="w-4 h-4" />
        </Button>
      </Tooltip>

      <Tooltip content="分享">
        <Button variant="ghost" size="icon">
          <Share2 className="w-4 h-4" />
        </Button>
      </Tooltip>

      <div className="w-px h-6 bg-border mx-1" />

      <Tooltip content="删除" side="bottom">
        <Button variant="ghost" size="icon">
          <Trash2 className="w-4 h-4 text-destructive" />
        </Button>
      </Tooltip>
    </div>
  );
}

Table Usage

在表格中使用 Tooltip 显示额外信息。

姓名邮箱状态
张三zhangsan@example.com激活
李四lisi@example.com未激活
王五wangwu@example.com激活
"use client";

import { Tooltip } from "@/components/composed/tooltip/tooltip";

/**
 * 表格中的 Tooltip 示例
 */
export function TooltipTable() {
  const data = [
    { id: 1, name: "张三", email: "zhangsan@example.com", status: "active" },
    { id: 2, name: "李四", email: "lisi@example.com", status: "inactive" },
    { id: 3, name: "王五", email: "wangwu@example.com", status: "active" },
  ];

  return (
    <div className="rounded-md border">
      <table className="w-full text-sm">
        <thead>
          <tr className="border-b bg-muted/50">
            <th className="px-4 py-3 text-left font-medium">姓名</th>
            <th className="px-4 py-3 text-left font-medium">邮箱</th>
            <th className="px-4 py-3 text-left font-medium">状态</th>
          </tr>
        </thead>
        <tbody>
          {data.map((row) => (
            <tr key={row.id} className="border-b last:border-0">
              <td className="px-4 py-3">
                <Tooltip content={`用户 ID: ${row.id}`} side="right">
                  <span className="cursor-help">{row.name}</span>
                </Tooltip>
              </td>
              <td className="px-4 py-3">
                <Tooltip content="点击复制邮箱地址" side="top">
                  <span className="cursor-help text-muted-foreground">
                    {row.email}
                  </span>
                </Tooltip>
              </td>
              <td className="px-4 py-3">
                <Tooltip
                  content={
                    row.status === "active" ? "用户已激活" : "用户未激活"
                  }
                  side="left"
                >
                  <span
                    className={`inline-flex items-center px-2 py-1 rounded-full text-xs font-medium cursor-help ${
                      row.status === "active"
                        ? "bg-green-50 text-green-700"
                        : "bg-gray-50 text-gray-700"
                    }`}
                  >
                    {row.status === "active" ? "激活" : "未激活"}
                  </span>
                </Tooltip>
              </td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

Form Help Text

在表单中使用 Tooltip 提供帮助信息。

"use client";

import { Tooltip } from "@/components/composed/tooltip/tooltip";
import { Button } from "@/components/ui/button";
import { Info } from "lucide-react";

/**
 * 表单中的 Tooltip 示例
 */
export function TooltipForm() {
  return (
    <div className="max-w-md space-y-4">
      <div className="space-y-2">
        <label className="flex items-center gap-2 text-sm font-medium">
          用户名
          <Tooltip content="用户名必须为 3-20 个字符,只能包含字母、数字和下划线">
            <Info className="w-4 h-4 text-muted-foreground cursor-help" />
          </Tooltip>
        </label>
        <input
          type="text"
          placeholder="请输入用户名"
          className="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-primary"
        />
      </div>

      <div className="space-y-2">
        <label className="flex items-center gap-2 text-sm font-medium">
          邮箱地址
          <Tooltip content="我们会向此邮箱发送验证码" side="right">
            <Info className="w-4 h-4 text-muted-foreground cursor-help" />
          </Tooltip>
        </label>
        <input
          type="email"
          placeholder="example@email.com"
          className="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-primary"
        />
      </div>

      <div className="space-y-2">
        <label className="flex items-center gap-2 text-sm font-medium">
          密码
          <Tooltip
            content="密码至少 8 位,必须包含大小写字母、数字和特殊字符"
            side="bottom"
          >
            <Info className="w-4 h-4 text-muted-foreground cursor-help" />
          </Tooltip>
        </label>
        <input
          type="password"
          placeholder="请输入密码"
          className="w-full px-3 py-2 border rounded-md focus:outline-none focus:ring-2 focus:ring-primary"
        />
      </div>

      <Button className="w-full">提交</Button>
    </div>
  );
}

自定义触发时机

import { Tooltip } from "@/registry/wuhan/composed/tooltip";

function CustomTrigger() {
  return (
    <Tooltip content="自定义延迟" delayDuration={500}>
      <Button>延迟 500ms 显示</Button>
    </Tooltip>
  );
}

富文本内容

import { Tooltip } from "@/registry/wuhan/composed/tooltip";

function RichContent() {
  return (
    <Tooltip
      content={
        <div className="space-y-1">
          <div className="font-semibold">快捷键</div>
          <div className="text-xs">⌘ + K 打开搜索</div>
        </div>
      }
    >
      <Button variant="outline">快捷键</Button>
    </Tooltip>
  );
}

条件显示

import { Tooltip } from "@/registry/wuhan/composed/tooltip";

function ConditionalTooltip({ showTooltip }: { showTooltip: boolean }) {
  const button = <Button>悬停查看</Button>;
  
  if (!showTooltip) {
    return button;
  }
  
  return (
    <Tooltip content="这是提示信息">
      {button}
    </Tooltip>
  );
}

与其他组件结合

import { Tooltip } from "@/registry/wuhan/composed/tooltip";
import { Badge } from "@/components/ui/badge";

function CombinedComponents() {
  return (
    <div className="flex items-center gap-2">
      <span>状态:</span>
      <Tooltip content="项目当前处于开发阶段" side="right">
        <Badge variant="secondary" className="cursor-help">
          开发中
        </Badge>
      </Tooltip>
    </div>
  );
}

动态内容

import { Tooltip } from "@/registry/wuhan/composed/tooltip";
import { useState } from "react";

function DynamicContent() {
  const [count, setCount] = useState(0);
  
  return (
    <Tooltip content={`点击次数:${count}`}>
      <Button onClick={() => setCount(count + 1)}>
        点击我
      </Button>
    </Tooltip>
  );
}

多语言支持

import { Tooltip } from "@/registry/wuhan/composed/tooltip";
import { useTranslation } from "react-i18next";

function I18nTooltip() {
  const { t } = useTranslation();
  
  return (
    <Tooltip content={t("tooltip.help")}>
      <Button>{t("button.help")}</Button>
    </Tooltip>
  );
}