Skip to content
Lenso UI

Tooltip 工具提示

当用户悬停或聚焦某个元素时,展示提示性文本。

用法

import { Tooltip } from '@lenso/ui';

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";
// Adapted from HeroUI v3.2.6 tooltip-basic (Apache-2.0).import { CircleInfo } from "@gravity-ui/icons";import * as stylex from "@stylexjs/stylex";import { Button, Tooltip } from "@lenso/ui";import { useId } from "react";
const styles = stylex.create({ row: { display: "flex", alignItems: "center", gap: 16 } });
export function TooltipBasic() {  const textId = useId();  const informationId = useId();  return (    <Tooltip.Provider delay={0}>      <div {...stylex.props(styles.row)}>        <Tooltip>          <Tooltip.Trigger aria-describedby={textId} render={<Button variant="secondary" />}>            Hover me          </Tooltip.Trigger>          <Tooltip.Portal>            <Tooltip.Positioner>              <Tooltip.Popup id={textId}>This is a tooltip</Tooltip.Popup>            </Tooltip.Positioner>          </Tooltip.Portal>        </Tooltip>        <Tooltip>          <Tooltip.Trigger            aria-describedby={informationId}            render={<Button isIconOnly aria-label="More information" variant="tertiary" />}          >            <CircleInfo />          </Tooltip.Trigger>          <Tooltip.Portal>            <Tooltip.Positioner>              <Tooltip.Popup id={informationId}>More information</Tooltip.Popup>            </Tooltip.Positioner>          </Tooltip.Portal>        </Tooltip>      </div>    </Tooltip.Provider>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

组件结构

import { Tooltip, Button } from '@lenso/ui';
export default () => (  <Tooltip>    <Tooltip.Trigger>      <Button>Hover for tooltip</Button>    </Tooltip.Trigger>    <Tooltip.Content>      <Tooltip.Arrow />      关于此元素的有用信息    </Tooltip.Content>  </Tooltip>)

示例

位置

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";
// Adapted from HeroUI v3.2.6 tooltip-placement (Apache-2.0).import { Button, Tooltip } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";import { useId } from "react";import { tokens } from "@lenso/tokens/tokens.stylex.const";
const styles = stylex.create({  grid: { display: "grid", gridTemplateColumns: "repeat(3, minmax(0, 1fr))", gap: 16 },  center: { display: "flex", alignItems: "center", justifyContent: "center" },  caption: { fontSize: 14, color: tokens.muted },  button: { width: "100%" },});
function Placement({ side, label }: { side: "top" | "left" | "right" | "bottom"; label: string }) {  const id = useId();  return (    <Tooltip>      <Tooltip.Trigger        delay={0}        aria-describedby={id}        render={<Button variant="tertiary" xstyle={styles.button} />}      >        {label}      </Tooltip.Trigger>      <Tooltip.Portal>        <Tooltip.Positioner side={side} sideOffset={7}>          <Tooltip.Popup id={id}>            <Tooltip.Arrow />            <p>{label} placement</p>          </Tooltip.Popup>        </Tooltip.Positioner>      </Tooltip.Portal>    </Tooltip>  );}
export function TooltipPlacement() {  return (    <div {...stylex.props(styles.grid)}>      <div />      <Placement side="top" label="Top" />      <div />      <Placement side="left" label="Left" />      <div {...stylex.props(styles.center)}>        <span {...stylex.props(styles.caption)}>Hover buttons</span>      </div>      <Placement side="right" label="Right" />      <div />      <Placement side="bottom" label="Bottom" />      <div />    </div>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

带箭头

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";
// Adapted from HeroUI v3.2.6 tooltip-with-arrow (Apache-2.0).import { Button, Tooltip } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";import { useId } from "react";
const styles = stylex.create({ row: { display: "flex", alignItems: "center", gap: 16 } });
export function TooltipWithArrow() {  const arrowId = useId();  const offsetId = useId();  return (    <div {...stylex.props(styles.row)}>      <Tooltip>        <Tooltip.Trigger          delay={0}          aria-describedby={arrowId}          render={<Button variant="secondary" />}        >          With Arrow        </Tooltip.Trigger>        <Tooltip.Portal>          <Tooltip.Positioner sideOffset={7}>            <Tooltip.Popup id={arrowId}>              <Tooltip.Arrow />              <p>Tooltip with arrow indicator</p>            </Tooltip.Popup>          </Tooltip.Positioner>        </Tooltip.Portal>      </Tooltip>      <Tooltip>        <Tooltip.Trigger          delay={0}          aria-describedby={offsetId}          render={<Button variant="primary" />}        >          Custom Offset        </Tooltip.Trigger>        <Tooltip.Portal>          <Tooltip.Positioner sideOffset={12}>            <Tooltip.Popup id={offsetId}>              <Tooltip.Arrow />              <p>Custom offset from trigger</p>            </Tooltip.Popup>          </Tooltip.Positioner>        </Tooltip.Portal>      </Tooltip>    </div>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

自定义触发

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";
// Adapted from HeroUI v3.2.6 tooltip-custom-trigger (Apache-2.0).import { CircleCheckFill, CircleQuestion } from "@gravity-ui/icons";import { Avatar, Chip, Tooltip } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";import { useId } from "react";import { tokens } from "@lenso/tokens/tokens.stylex.const";
const ping = stylex.keyframes({  "75%": { transform: "scale(2)", opacity: 0 },  "100%": { transform: "scale(2)", opacity: 0 },});const styles = stylex.create({  row: { display: "flex", alignItems: "center", gap: 24 },  profile: { display: "flex", flexDirection: "column", gap: 0, paddingBlock: 4 },  strong: { fontWeight: 600 },  email: { fontSize: 12, color: tokens.muted },  status: { display: "flex", alignItems: "center", gap: 6 },  dot: { position: "relative", display: "flex", width: 8, height: 8 },  pulse: {    position: "absolute",    display: "inline-flex",    width: "100%",    height: "100%",    borderRadius: "50%",    backgroundColor: tokens.success,    opacity: 0.75,    animationName: { default: ping, "@media (prefers-reduced-motion: reduce)": "none" },    animationDuration: "1s",    animationTimingFunction: "cubic-bezier(0, 0, .2, 1)",    animationIterationCount: "infinite",  },  dotCenter: {    position: "relative",    display: "inline-flex",    width: 8,    height: 8,    borderRadius: "50%",    backgroundColor: tokens.success,  },  iconBackground: { borderRadius: "50%", backgroundColor: tokens.accentSoft, padding: 8 },  icon: { color: tokens.accentSoftForeground },  help: { maxWidth: 320, paddingInline: 4, paddingBlock: 6 },  helpHeading: { marginBottom: 4, fontWeight: 600 },  helpText: { fontSize: 14, color: tokens.muted },});
export function TooltipCustomTrigger() {  const avatarId = useId();  const statusId = useId();  const infoId = useId();  return (    <div {...stylex.props(styles.row)}>      <Tooltip>        <Tooltip.Trigger delay={0} aria-label="User avatar" aria-describedby={avatarId}>          <Avatar size="sm">            <Avatar.Image              alt="Jane Doe"              src="https://img.heroui.chat/image/avatar?w=400&h=400&u=4"            />            <Avatar.Fallback>JD</Avatar.Fallback>          </Avatar>        </Tooltip.Trigger>        <Tooltip.Portal>          <Tooltip.Positioner sideOffset={7}>            <Tooltip.Popup id={avatarId}>              <Tooltip.Arrow />              <div {...stylex.props(styles.profile)}>                <p {...stylex.props(styles.strong)}>Jane Doe</p>                <p {...stylex.props(styles.email)}>[email protected]</p>              </div>            </Tooltip.Popup>          </Tooltip.Positioner>        </Tooltip.Portal>      </Tooltip>      <Tooltip>        <Tooltip.Trigger delay={0} aria-label="Status chip" aria-describedby={statusId}>          <Chip color="success">            <CircleCheckFill width={12} />            <Chip.Label>Active</Chip.Label>          </Chip>        </Tooltip.Trigger>        <Tooltip.Portal>          <Tooltip.Positioner>            <Tooltip.Popup id={statusId} xstyle={styles.status}>              <span {...stylex.props(styles.dot)} aria-hidden="true">                <span {...stylex.props(styles.pulse)} />                <span {...stylex.props(styles.dotCenter)} />              </span>              <p>Jane is currently online</p>            </Tooltip.Popup>          </Tooltip.Positioner>        </Tooltip.Portal>      </Tooltip>      <Tooltip>        <Tooltip.Trigger delay={0} aria-label="Info icon" aria-describedby={infoId}>          <div {...stylex.props(styles.iconBackground)}>            <CircleQuestion {...stylex.props(styles.icon)} />          </div>        </Tooltip.Trigger>        <Tooltip.Portal>          <Tooltip.Positioner sideOffset={7}>            <Tooltip.Popup id={infoId}>              <Tooltip.Arrow />              <div {...stylex.props(styles.help)}>                <p {...stylex.props(styles.helpHeading)}>Help Information</p>                <p {...stylex.props(styles.helpText)}>                  This is a helpful tooltip with more detailed information about this feature.                </p>              </div>            </Tooltip.Popup>          </Tooltip.Positioner>        </Tooltip.Portal>      </Tooltip>    </div>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

渲染函数

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";
// Adapted from HeroUI v3.2.6 tooltip-render-function (Apache-2.0).import { CircleInfo } from "@gravity-ui/icons";import { Button, Tooltip } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";import { useId } from "react";
const styles = stylex.create({ row: { display: "flex", alignItems: "center", gap: 16 } });
export function RenderFunction() {  const textId = useId();  const informationId = useId();  return (    <div {...stylex.props(styles.row)}>      <Tooltip>        <Tooltip.Trigger          delay={0}          aria-describedby={textId}          render={<Button variant="secondary" />}        >          Hover me        </Tooltip.Trigger>        <Tooltip.Portal>          <Tooltip.Positioner>            <Tooltip.Popup id={textId} render={(props) => <div {...props} data-custom="foo" />}>              <p>This is a tooltip</p>            </Tooltip.Popup>          </Tooltip.Positioner>        </Tooltip.Portal>      </Tooltip>      <Tooltip>        <Tooltip.Trigger          delay={0}          aria-describedby={informationId}          render={<Button isIconOnly aria-label="More information" variant="tertiary" />}        >          <CircleInfo />        </Tooltip.Trigger>        <Tooltip.Portal>          <Tooltip.Positioner>            <Tooltip.Popup              id={informationId}              render={(props) => <div {...props} data-custom="foo" />}            >              <p>More information</p>            </Tooltip.Popup>          </Tooltip.Positioner>        </Tooltip.Portal>      </Tooltip>    </div>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

自定义样式

Tailwind CSS

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";
// Adapted from HeroUI v3.2.6 tooltip-custom-styles (Apache-2.0).import { Button, Tooltip } from "@lenso/ui";import * as stylex from "@stylexjs/stylex";import { useId } from "react";import { tokens } from "@lenso/tokens/tokens.stylex.const";
const styles = stylex.create({  popup: {    borderRadius: tokens.radiusLg,    borderWidth: 1,    borderStyle: "solid",    borderColor: "color-mix(in oklab, var(--border) 80%, transparent)",    backgroundColor: tokens.surface,    paddingInline: 10,    paddingBlock: 4,    fontSize: 12,    color: tokens.foreground,    boxShadow: "0 1px 2px 0 rgb(0 0 0 / 0.05)",  },});
export function CustomStyles() {  const id = useId();  return (    <Tooltip>      <Tooltip.Trigger delay={0} aria-describedby={id} render={<Button variant="secondary" />}>        Share link      </Tooltip.Trigger>      <Tooltip.Portal>        <Tooltip.Positioner>          <Tooltip.Popup id={id} xstyle={styles.popup}>            <p>Copied to clipboard</p>          </Tooltip.Popup>        </Tooltip.Positioner>      </Tooltip.Portal>    </Tooltip>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

全局 CSS

若要自定义组件类,可使用 @layer components 指令。了解更多。

@layer components {  .tooltip {    @apply rounded-xl shadow-lg;  }
  .tooltip__trigger {    @apply cursor-help;  }}

样式参考

HeroUI 遵循 BEM 方法论,确保组件变体与状态可复用且易于自定义。

全局延迟配置

你可以通过定义 CSS 变量,为应用中所有 Tooltip 设置默认的显示与隐藏延迟:

/* 在你的全局 CSS 文件中 */:root {  --tooltip-delay: 1500ms;  --tooltip-close-delay: 500ms;}
/* 也可以为浅色/深色主题设置不同的值 */.light, [data-theme="light"] {  --tooltip-delay: 1200ms;}
.dark, [data-theme="dark"] {  --tooltip-close-delay: 300ms;}

值支持 ms、s 等 CSS 时间单位。在单个 Tooltip 上指定 delay 或 closeDelay 时,会覆盖这些全局设置。

CSS 类

Tooltip 使用以下 CSS 类(查看源码样式):

基础类 [!toc]

  • .tooltip - 带动画的基础 Tooltip 样式
  • .tooltip__trigger - 触发元素样式

交互状态

组件支持以下动画相关状态:

  • 进入:[data-entering] — Tooltip 出现过程中应用
  • 离开:[data-exiting] — Tooltip 消失过程中应用
  • 位置:[data-placement="*"] — 根据 Tooltip 位置应用

API 参考

Tooltip

Prop类型默认值描述
childrenReact.ReactNode-触发元素与内容
delaynumber1500 或 CSS 变量显示 Tooltip 前的延迟(毫秒);可通过 --tooltip-delay CSS 变量全局配置
closeDelaynumber500 或 CSS 变量隐藏 Tooltip 前的延迟(毫秒);可通过 --tooltip-close-delay CSS 变量全局配置
trigger"hover" | "focus""hover"Tooltip 的触发方式
isDisabledbooleanfalse是否禁用 Tooltip
shouldSkipAnimationbooleanfalse在多个 Tooltip 之间快速切换时,是否跳过进入与退出动画

Tooltip.Content

Prop类型默认值描述
childrenReact.ReactNode-在 Tooltip 中展示的内容
showArrowbooleanfalse是否显示箭头指示器
offsetnumber3(带箭头时为 7)与触发元素的距离
placement"top" | "bottom" | "left" | "right" (及变体)"top"Tooltip 的位置
classNamestring-额外的 CSS 类名
renderDOMRenderFunction<keyof React.JSX.IntrinsicElements, TooltipRenderProps>-通过自定义渲染函数覆盖默认的 DOM 元素。

Tooltip.Trigger

Prop类型默认值描述
childrenReact.ReactNode-触发 Tooltip 的元素
classNamestring-额外的 CSS 类名

Tooltip.Arrow

Prop类型默认值描述
childrenReact.ReactNode-自定义箭头元素
classNamestring-额外的 CSS 类名
renderDOMRenderFunction<keyof React.JSX.IntrinsicElements, OverlayArrowRenderProps>-通过自定义渲染函数覆盖默认的 DOM 元素。

相关组件