Tooltip 文字提示

悬停或聚焦时显示的简短说明。

import { Bold, Italic, Link2, Strikethrough } from 'lucide-react'
import { ButtonGroup, IconButton } from '@hina-ui/react'

export default function Demo() {
  return (
    <ButtonGroup label="文字格式">
      <IconButton label="加粗" variant="outline">
        <Bold />
      </IconButton>
      <IconButton label="斜体" variant="outline">
        <Italic />
      </IconButton>
      <IconButton label="删除线" variant="outline">
        <Strikethrough />
      </IconButton>
      <IconButton label="插入链接" variant="outline">
        <Link2 />
      </IconButton>
    </ButtonGroup>
  )
}
tsx

用法

import { Tooltip } from '@hina-ui/react'
ts

children 是触发器,content 属性是提示的文字。指针悬停或键盘聚焦时显示,指针移开或按 Esc 时隐藏。

import { Button, Tooltip } from '@hina-ui/react'

export default function Demo() {
  return (
    <Tooltip content="保存后立刻发布">
      <Button variant="outline" tone="neutral">
        发布
      </Button>
    </Tooltip>
  )
}
tsx

IconButton 自带提示:label 既是无障碍名称,也是提示文字,不需要再包一层 Tooltip。

Tooltip 需要外层有 TooltipProvider,AppShell 已经包含了一个。没有 Provider 时,组件只渲染触发器。

示例

包裹已有元素

React 版没有提示指令,直接用 Tooltip 包裹已有元素。children 必须是单个能接收 ref 与事件属性的元素,原生元素与渲染为单一元素的组件都可以。content、side、disabled 等属性变化时提示同步更新。

禁用对象提示

'use client'

import { useState } from 'react'
import { Button, Inline, Input, Stack, Switch, Text, Tooltip } from '@hina-ui/react'

export default function Demo() {
  const [content, setContent] = useState('提示文字')
  const [disabled, setDisabled] = useState(false)
  return (
    <Stack align="start">
      <Inline>
        <Tooltip content="直接绑定已有元素">
          <Button variant="outline" tone="neutral">
            字符串
          </Button>
        </Tooltip>
        <Tooltip content={content} side="bottom" disabled={disabled}>
          <Button variant="outline" tone="neutral">
            对象配置
          </Button>
        </Tooltip>
      </Inline>
      <Input value={content} onValueChange={setContent} aria-label="提示文字" className="w-64" />
      <Inline>
        <Switch checked={disabled} onCheckedChange={setDisabled} aria-label="禁用对象提示" />
        <Text>禁用对象提示</Text>
      </Inline>
    </Stack>
  )
}
tsx

位置

side 指定提示出现在哪一侧,align 指定它与触发器的对齐方式。默认在正上方,空间不足时翻转到相反一侧。

import { Button, Inline, Tooltip } from '@hina-ui/react'

export default function Demo() {
  return (
    <Inline align="center" className="gap-6">
      <Tooltip content="浮在头顶" side="top">
        <Button variant="outline" tone="neutral">
          top
        </Button>
      </Tooltip>
      <Tooltip content="浮在右侧" side="right">
        <Button variant="outline" tone="neutral">
          right
        </Button>
      </Tooltip>
      <Tooltip content="浮在下方" side="bottom">
        <Button variant="outline" tone="neutral">
          bottom
        </Button>
      </Tooltip>
      <Tooltip content="与起始边对齐" side="top" align="start">
        <Button variant="outline" tone="neutral">
          top start
        </Button>
      </Tooltip>
    </Inline>
  )
}
tsx

间距

sideOffset 是提示与触发器之间的距离,单位为像素。

import { Button, Inline, Tooltip } from '@hina-ui/react'

export default function Demo() {
  return (
    <Inline align="center" className="gap-6">
      <Tooltip content="sideOffset 为 0" sideOffset={0}>
        <Button variant="outline" tone="neutral">
          紧贴
        </Button>
      </Tooltip>
      <Tooltip content="sideOffset 为 16" sideOffset={16}>
        <Button variant="outline" tone="neutral">
          远离
        </Button>
      </Tooltip>
    </Inline>
  )
}
tsx

提示内容

content 属性不限于文字,例如可以放快捷键。超过最大宽度的文字会自动换行。

import { Info, Save } from 'lucide-react'
import { IconButton, Inline, Kbd, Tooltip } from '@hina-ui/react'

export default function Demo() {
  return (
    <Inline align="center" className="gap-6">
      <Tooltip
        content={
          <Inline align="center" className="gap-1.5">
            保存草稿
            <Kbd>Ctrl S</Kbd>
          </Inline>
        }
      >
        <IconButton label="保存" variant="outline" tooltip={false}>
          <Save />
        </IconButton>
      </Tooltip>
      <Tooltip content="这段说明比较长,超过气泡的最大宽度之后会自动折成多行,不会一直往外撑。">
        <IconButton label="说明" variant="outline" tooltip={false}>
          <Info />
        </IconButton>
      </Tooltip>
    </Inline>
  )
}
tsx

延迟

delayDuration 是显示提示前的悬停时长。skipDelayDuration 是一个时间窗:提示关闭后的这段时间内移到下一个触发器,会跳过延迟直接显示。两者对 TooltipProvider 内的所有 Tooltip 生效。

import { Button, Inline, Tooltip, TooltipProvider } from '@hina-ui/react'

export default function Demo() {
  return (
    <TooltipProvider delayDuration={600} skipDelayDuration={0}>
      <Inline align="center" className="gap-6">
        <Tooltip content="等待 600 毫秒后出现">
          <Button variant="outline" tone="neutral">
            慢一点
          </Button>
        </Tooltip>
        <Tooltip content="同样等待 600 毫秒">
          <Button variant="outline" tone="neutral">
            再一个
          </Button>
        </Tooltip>
      </Inline>
    </TooltipProvider>
  )
}
tsx

受控

传入 open 后,显示与隐藏由调用方决定,悬停与键盘焦点不再起作用;受控时提示的定位改为逐帧更新,可以跟随移动中的触发器,Slider 的取值标签即采用这种方式。

'use client'

import { useState } from 'react'
import { Button, Inline, Switch, Tooltip } from '@hina-ui/react'

export default function Demo() {
  const [shown, setShown] = useState(true)
  return (
    <Inline gap="lg" align="center">
      <Tooltip content="由右边的开关控制" open={shown}>
        <Button variant="outline" tone="neutral">
          提示的触发器
        </Button>
      </Tooltip>
      <Switch checked={shown} onCheckedChange={setShown}>
        显示提示
      </Switch>
    </Inline>
  )
}
tsx

禁用

设置 disabled 后不创建浮层,只渲染触发器。

当前:已禁用

'use client'

import { useState } from 'react'
import { Button, Inline, Text, Tooltip } from '@hina-ui/react'

export default function Demo() {
  const [off, setOff] = useState(true)
  return (
    <Inline align="center">
      <Tooltip content="侧栏收起时才需要这句话" disabled={off}>
        <Button variant="outline" tone="neutral">
          悬停试试
        </Button>
      </Tooltip>
      <Button size="sm" variant="soft" tone="neutral" onClick={() => setOff(!off)}>
        {off ? '启用提示' : '禁用提示'}
      </Button>
      <Text tone="muted" size="sm">
        当前:{off ? '已禁用' : '已启用'}
      </Text>
    </Inline>
  )
}
tsx

行为

  • 只有来自键盘的焦点会显示提示;鼠标点击留下的焦点、浮层关闭后归还的焦点都不会。
  • 提示不会锁定页面滚动,页面滚动时它跟随触发器。

无障碍

  • 触发器的 aria-describedby 指向提示,屏幕阅读器读完触发器后会读出提示。
  • 提示不获得焦点,也不在 Tab 顺序中。需要交互的内容应放在 Popover 里。

API

Tooltip

属性
类型
默认值
说明
content
ReactNode
—
提示的内容,可以是文字或其他元素
side
'top' | 'right' | 'bottom' | 'left'
'top'
出现在哪一侧
align
'start' | 'center' | 'end'
'center'
与触发器的对齐方式
sideOffset
number
8
与触发器的距离
open
boolean
—
受控的显示状态,未传入时由悬停与键盘焦点决定
disabled
boolean
false
是否禁用提示
className
string
—
追加到提示上的类名
children
ReactElement
—
触发器,必须是单个元素

TooltipProvider

属性
类型
默认值
说明
delayDuration
number
150
显示提示前的悬停时长,单位为毫秒
skipDelayDuration
number
300
跳过延迟的时间窗,单位为毫秒
属性
说明
children
共用这两个时长的子树