wui
组件

文字提示 Tooltip

在悬停或键盘聚焦时,为控件补充简短的上下文说明。

基础示例

Loading…
pnpm dlx wui@latest add @wui/tooltip
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 rounded-md bg-foreground font-medium text-background shadow-md outline-none will-change-[transform,opacity] data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=delayed-open]:animate-in data-[state=delayed-open]:fade-in-0 data-[state=delayed-open]:zoom-in-95 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 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,
}

组件作用

Tooltip 用于解释图标按钮、不熟悉的控件或被截断的内容。它是辅助信息,不能承载完成任务所必需的内容,也不能替代可见标签、错误提示或 Popover 中的可交互内容。基于 Radix 的实现同时支持指针悬停、键盘聚焦、触屏行为与碰撞检测。

组件属性

PropTypeDefaultDescription
openbooleanControlled open state.
defaultOpenbooleanfalseInitial open state when uncontrolled.
onOpenChange((open: boolean) => void)Called whenever the open state changes.
delayDurationnumberHover delay in milliseconds for this tooltip.
disableHoverableContentbooleanfalseClose when the pointer leaves the trigger instead of allowing content hover.
  • TooltipProvider 通过 delayDurationskipDelayDuration 协调一组提示的打开节奏。
  • Tooltip 支持 opendefaultOpenonOpenChange 和单实例的 delayDuration
  • TooltipTrigger 支持 asChild,可将触发能力附加到现有按钮或链接。
  • TooltipContent 提供 sidealignsideOffsetsize="sm | default"showArrow

事件

  • onOpenChange(open):提示因悬停、焦点或关闭操作改变状态时触发。
  • onEscapeKeyDown(event):内容打开时按下 Escape 触发,可调用 event.preventDefault() 阻止默认关闭行为。
  • onPointerDownOutside(event):在提示范围外按下指针时触发。

其余指针、焦点和无障碍属性会透传给对应的 Radix 部件。

拓展使用

定位、尺寸与箭头

Loading…

通过 side="top | right | bottom | left" 指定首选方向;空间不足时 Radix 会自动避让。密集工具栏可使用 size="sm",无须方向强调时可设置 showArrow={false}

一组相邻提示应共享同一个 TooltipProvider,这样用户从一个触发器移动到另一个触发器时,不必重复等待完整的打开延迟。