@ data- slot/ tabletip
香草JavaScript的无头工具提示组件. 无障碍而无作相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相相.
安装
npm install @data-slot/tooltip
快速启动
<div data-slot="tooltip">
<button data-slot="tooltip-trigger">Hover me</button>
<div data-slot="tooltip-content" hidden>
Helpful tooltip text
</div>
</div>
<script type="module">
import { create } from "@data-slot/tooltip";
const controllers = create();
</script>
API 密码
初始化
create(scope?)
自动发现并绑定一个范围内的所有工具提示实例(默认为 document) (中文(简体) ).
import { create } from "@data-slot/tooltip";
const controllers = create(); // Returns TooltipController[]
createTooltip(root, options?)
为特定元素创建控制器.
import { createTooltip } from "@data-slot/tooltip";
const tooltip = createTooltip(element, {
delay: 300,
skipDelayDuration: 300,
side: "top",
align: "center",
onOpenChange: (open) => console.log(open),
});
槽数
运行时间槽
tooltip- 管理开放状态和徘徊延迟的根元素.tooltip-trigger- 在悬浮或焦点上打开工具提示并与其描述相链接的必要元素.tooltip-content- 需要带有工具提示语义的浮动面板.tooltip-arrow- 内容内的可选箭头,以运行时间对准触发器.tooltip-positioner- 内容周围可选作者定位包装,再利用而不是生成包装.tooltip-portal- 可选作者的门户包装,可以包含位置和内容.
标记
<div data-slot="tooltip">
<button data-slot="tooltip-trigger">Trigger</button>
<div data-slot="tooltip-content">
Content
<div data-slot="tooltip-arrow"></div>
</div>
</div>
由门户网站标记( 可选)
<div data-slot="tooltip">
<button data-slot="tooltip-trigger">Trigger</button>
<div data-slot="tooltip-portal">
<div data-slot="tooltip-positioner">
<div data-slot="tooltip-content">
Content
<div data-slot="tooltip-arrow"></div>
</div>
</div>
</div>
</div>
数据属性
选项也可以通过数据属性设定. 联合来文的选择优先.
放置属性( A)data-side, (中文(简体) ), data-align, (中文(简体) ), data-side-offset, (中文(简体) ), data-align-offset, (中文(简体) ), data-avoid-collisions, (中文(简体) ), data-collision-padding(a) 决定按此顺序:
- JavaScript 选项
tooltip-contenttooltip-positionertooltip根 (倒计时)
| 属性 | 类型 | 默认 | 说明 |
|---|---|---|---|
data-delay | 编号 | 300 | 显示工具提示前的延迟( ms) |
data-skip-delay-duration | 编号 | 300 | 关闭后跳过延迟的时间( 毫秒) |
data-side | 字符串 | "top" | 边相对触发( N)top, (中文(简体) ), right, (中文(简体) ), bottom, (中文(简体) ), left, (中文(简体) ), inline-start, (中文(简体) ), inline-end(中文(简体) ) |
data-align | 字符串 | "center" | 沿边对齐 |
data-side-offset | 编号 | 4 | 距离触发器( px) |
data-align-offset | 编号 | 0 | 对齐边偏移 (px) |
data-avoid-collisions | 布尔 | true | 碰撞处理 |
data-collision-padding | 编号 | 8 | 查看端口边缘粘贴 (px) |
data-portal | 布尔 | true | 打开时的门户 |
data-mount-strategy (基层) | "lazy" | "eager" | "lazy" | 删除已关闭的内容, 或者保留在文档中 |
<!-- Tooltip with faster response -->
<div data-slot="tooltip" data-delay="100">
...
</div>
<!-- Disable warm-up behavior -->
<div data-slot="tooltip" data-skip-delay-duration="0">
...
</div>
<!-- Side/align and offsets on content element -->
<div
data-slot="tooltip-content"
data-side="bottom"
data-align="start"
data-side-offset="8"
data-align-offset="4"
>
...
</div>
输出属性
组件自动设置这些属性 :
| 元素 | 属性 | 数值 |
|---|---|---|
| 根号 | data-state | "open" | "closed" (遗产相容性) |
| 根号 | data-open 编号 : data-closed | 匹配状态时显示 |
| 根号 | data-instant | "delay" | "focus" | "dismiss" |
| 内容 | data-state | "open" | "closed" (遗产相容性) |
| 内容 | data-open 编号 : data-closed | 匹配状态时显示 |
| 内容 | data-starting-style | 开幕时在场 |
| 内容 | data-ending-style | 结束时在场 |
| 内容 | data-instant | "delay" | "focus" | "dismiss" |
| 内容 | data-side | "top" | "right" | "bottom" | "left" | "inline-start" | "inline-end" |
| 内容 | data-align | "start" | "center" | "end" |
| 内容 | role | "tooltip" |
| 内容 | aria-hidden | "true" 当关闭时, "false" 打开时 |
| 定位器 | data-open 编号 : data-closed | 匹配状态时显示 |
| 定位器 | data-instant | "delay" | "focus" | "dismiss" |
| 定位器 | data-side | "top" | "right" | "bottom" | "left" | "inline-start" | "inline-end" |
| 定位器 | data-align | "start" | "center" | "end" |
| 箭头 | data-open 编号 : data-closed | 匹配状态时显示 |
| 箭头 | data-instant | "delay" | "focus" | "dismiss" |
| 箭头 | data-side | "top" | "right" | "bottom" | "left" | "inline-start" | "inline-end" |
| 箭头 | data-align | "start" | "center" | "end" |
| 箭头 | data-uncentered | 当箭头无法完美地居中时显示 |
| 箭头 | aria-hidden | "true" |
| 触发 | aria-describedby | 打开时内容ID, 关闭时删除 |
选项
| 选项 | 类型 | 默认 | 说明 |
|---|---|---|---|
delay | number | 300 | 显示工具提示前的延迟( ms) |
skipDelayDuration | number | 300 | 关闭后跳过延迟的时间(毫秒) 。 设定为 0 以禁用热身. |
side | "top" | "right" | "bottom" | "left" | "inline-start" | "inline-end" | "top" | 首选边相对触发 |
align | "start" | "center" | "end" | "center" | 首选对齐 |
sideOffset | number | 4 | 距离像素触发器 |
alignOffset | number | 0 | 从像素中的对齐边缘抵消 |
avoidCollisions | boolean | true | 翻转/移入景点 |
collisionPadding | number | 8 | 以像素为单位的视图端点 |
portal | boolean | true | 门户内容到 document.body 打开时 |
mountStrategy | "lazy" | "eager" | "lazy" | 解密内容;JS 覆盖根 data-mount-strategy |
onOpenChange | (open: boolean) => void | undefined | 可见度改变时召回 |
说明: side 财务报告和审定财务报表 align 在约束时间内解决的首选放置输入。 随着碰撞处理的启用,计算 data-side 运行时间可能有所不同.
主计长
| 方法/财产 | 说明 |
|---|---|
show() | 立即显示工具提示 。 尊重残疾状态. |
hide() | 隐藏工具提示 |
isOpen | 当前能见度状态( 只读) boolean(中文(简体) ) |
destroy() | 清理所有事件听众和计时器 |
主计长销毁
destroy() 永久处理控制器并隐藏任何打开的表面,而不包含
产生额外的变化事件。 重复销毁是安全的
旧控制器变成无操作器。 在同一根上创建新控制器以重新组合 .
清除此工具提示添加的描述引用并保存
其他作者 aria-describedby 参考文献。 作者对工具提示的引用
它本身被中止,而其内容被剥离,并在被破坏后恢复.
内容安装和服务器渲染
默认情况下, Tooltip会从页面的 DOM 中删除其隐藏信件. 一直这样 初始化后有许多更小的工具提示的页面。 按钮或其他元素 打开页面中的工具提示.
显示工具提示将相同的消息放回页面. 其状态和活动 听众被保存下来。 隐藏它等待任何退出动画完成之前 把它拿开 如果工具提示在动画中再次打开,它会留在 页 次.
大多数应用程序可以不作任何修改地使用此默认值.
如果您的代码需要在隐藏工具提示时找到或更新信件 - for
实例,使用 querySelector——使用 eager 模式将其保存在 DOM 中 :
createTooltip(root, { mountStrategy: "eager" });
您还可以添加 data-mount-strategy="eager" 到工具提示根。 一个 Java 脚本
选项优先于 HTML 属性.
默认 lazy 模式, DOM 查询找不到隐藏信件 。 狦
您只需更改其文本,也可以保留信件元素的引用
在初始化工具提示之前,并在稍后使用该引用.
没有 JavaScript 的服务器渲染和页面
懒散的升起 没有 减少发送给浏览器的 HTML 。 讯息是 仍然包含在您的 HTML; 工具提示在 JavaScript 之后从 DOM 中删除 初始化 .
将工具提示的初始标记隐藏起来, 防止它在之前短暂出现
初始化。 打开的按钮或元素必须具有清晰的可访问性
名称。 使用工具提示获取额外信息, 并保留任何必要的信息
可用而不打开它。 也没有 lazy 也没有 eager 模式使工具提示工作
没有JavaScript.
活动
境外事件
通过自定义事件聆听更改 :
element.addEventListener("tooltip:change", (e) => {
const { open, trigger, content, reason } = e.detail;
console.log(`Tooltip ${open ? 'opened' : 'closed'} via ${reason}`);
});
事件详情
| 财产 | 类型 | 说明 |
|---|---|---|
open | boolean | 当前可见度状态 |
trigger | HTMLElement | 触发元素 |
content | HTMLElement | 内容要素 |
reason | string | 是什么导致了变化: "pointer", (中文(简体) ), "focus", (中文(简体) ), "blur", (中文(简体) ), "escape", (中文(简体) ), "api" |
入境事件
通过事件控制工具提示 :
| 活动 | 细节 | 说明 |
|---|---|---|
tooltip:set | { open: boolean } | 方案设定可见度 |
// Show the tooltip
element.dispatchEvent(
new CustomEvent("tooltip:set", { detail: { open: true } })
);
// Hide the tooltip
element.dispatchEvent(
new CustomEvent("tooltip:set", { detail: { open: false } })
);
说明: 打开纪念已禁用状态( 触发状态 ) disabled 属性或 aria-disabled="true") (中文(简体) ). 关闭总是允许的.
折旧形状
下列属性和形状被去化并会在v1.0中被去除:
- 遗产
data-state="open|closed"结构化tooltip根和块tooltip-content
使用 data-open 编号 : data-closed, (中文(简体) ), data-starting-style, (中文(简体) ), data-ending-style,以及 data-instant 换句话说.
// Deprecated: { value: boolean }
element.dispatchEvent(
new CustomEvent("tooltip:set", { detail: { value: true } })
);
使用 { open: boolean } 换句话说.
样式
位置在 JavaScript 中计算并应用到定位器中 position: absolute + 键 transform: translate3d(...)。 。 。 .
默认情况下,内容被传送到 document.body 并打开.
定位要素tooltip-positioner,或 tooltip-content 何时 portal 已禁用)获得 --transform-origin,哪个 tooltip-content 可以通过 CSS 继承来用于转换动画.
使用 data-open 编号 : data-closed, (中文(简体) ), data-starting-style 编号 : data-ending-style, (中文(简体) ), data-side, (中文(简体) ), data-align,以及 data-instant 用于造型和动画.
定位使用布局尺寸,所以 scale编号 :zoom 动画打开 tooltip-content 保持稳定,不增加额外包装.
工具提示箭头几何是运行时拥有的 : 控制器内置 top 编号 : left 坐标和坐标 position: absolute 打开 tooltip-arrow. CSS只应处理边缘附件、旋转和可选的化妆品软糖。 避免将箭头横轴与帮助者比对 top-1/2, (中文(简体) ), left-1/2,或 -translate-y-1/2。 。 。 .
建议支助科
下面的例子符合 Base/shadcn 构成样式:真实 tooltip-arrow,逻辑侧支持,并估值 data-instant。 。 。 .
[data-slot="tooltip-content"] {
position: absolute;
display: inline-flex;
align-items: center;
gap: 0.375rem;
padding: 0.375rem 0.75rem;
font-size: 0.75rem;
white-space: nowrap;
background: #111827;
color: white;
opacity: 0;
visibility: hidden;
pointer-events: none;
transform-origin: var(--transform-origin, center center);
--tooltip-slide-x: 0px;
--tooltip-slide-y: 0px;
transition: opacity 0.15s ease, visibility 0s linear 0.15s;
}
[data-slot="tooltip-content"][data-side="top"] { --tooltip-slide-y: 8px; }
[data-slot="tooltip-content"][data-side="bottom"] { --tooltip-slide-y: -8px; }
[data-slot="tooltip-content"][data-side="left"] { --tooltip-slide-x: 8px; }
[data-slot="tooltip-content"][data-side="right"] { --tooltip-slide-x: -8px; }
[data-slot="tooltip-content"][data-side="inline-start"] { --tooltip-slide-x: 8px; }
[data-slot="tooltip-content"][data-side="inline-end"] { --tooltip-slide-x: -8px; }
[data-slot="tooltip-content"][data-open] {
opacity: 1;
visibility: visible;
pointer-events: auto;
transition-delay: 0s;
}
[data-slot="tooltip-content"][data-closed] {
pointer-events: none;
}
[data-slot="tooltip-content"][data-instant] {
transition: none;
animation: none;
}
[data-slot="tooltip-arrow"] {
width: 0.625rem;
height: 0.625rem;
background: inherit;
transform: rotate(45deg);
}
[data-slot="tooltip-arrow"][data-side="top"] { bottom: -0.25rem; }
[data-slot="tooltip-arrow"][data-side="bottom"] { top: -0.25rem; }
[data-slot="tooltip-arrow"][data-side="left"] {
right: -0.25rem;
transform: translateX(-1.5px) rotate(45deg);
}
[data-slot="tooltip-arrow"][data-side="right"] {
left: -0.25rem;
transform: translateX(1.5px) rotate(45deg);
}
[data-slot="tooltip-arrow"][data-side="inline-start"] {
right: -0.25rem;
transform: translateX(-1.5px) rotate(45deg);
}
[data-slot="tooltip-arrow"][data-side="inline-end"] {
left: -0.25rem;
transform: translateX(1.5px) rotate(45deg);
}
尾风示例
使用内容和箭头数据属性进行开口状态样式:
<div data-slot="tooltip">
<button data-slot="tooltip-trigger">
Hover me
</button>
<div
data-slot="tooltip-content"
data-side="top"
class="px-2 py-1
bg-gray-900 text-white text-sm
opacity-0 pointer-events-none transition-opacity duration-150
data-[open]:opacity-100 data-[open]:pointer-events-auto
data-[instant]:transition-none"
>
Tooltip text
<div
data-slot="tooltip-arrow"
class="absolute size-2.5 rotate-45 bg-gray-900
data-[side=top]:-bottom-1
data-[side=bottom]:-top-1
data-[side=left]:-right-1
data-[side=left]:-translate-x-[1.5px]
data-[side=right]:-left-1
data-[side=right]:translate-x-[1.5px]
data-[side=inline-start]:-right-1
data-[side=inline-start]:-translate-x-[1.5px]
data-[side=inline-end]:-left-1
data-[side=inline-end]:translate-x-[1.5px]"
></div>
</div>
</div>
无障碍
该组件自动处理 :
role="tooltip"关于内容aria-describedby仅在打开时才启动(防止暂停通知)aria-hidden关于内容:明确"true"编号 :"false"为一致的AT行为- 内容独有的ID生成方式
ensureId
已禁用触发器
如果触发器有 disabled 属性或 aria-disabled="true"数字 :
- 指向和焦点事件不会打开工具提示
- 程序化
.show()也尊重残疾国家
行为
温暖的行为
当一个用户关闭一个工具提示并快速地徘徊另一个工具提示时,第二个工具提示立即显示(没有延迟). 这创造了类似于本地OS工具提示的流体浏览体验.
- 由
skipDelayDuration选项 - 设定为
0以禁用此行为 - 暖气打开,暖气关闭
data-instant="delay" - 焦点触发打开使用
data-instant="focus" - 解雇式关闭(例如)
Escape(a) 使用情况data-instant="dismiss" - 温暖窗口仅在工具提示实际关闭时设置( 不是在待定的打开被取消时)
互动模式
| 投入 | 行为 |
|---|---|
| 指针输入触发器( mouse/ pen) | 延迟后显示 |
| 指针离开触发器 | 立即隐藏( 除非输入内容) |
| 指针输入内容 | 保持开放( 可控内容) |
| 指针离开内容 | 立即隐藏( 除非输入触发) |
| 触摸悬浮 | 被忽略( 只聚焦于触摸设备) |
| 单击触发 | 取消尚未打开的已打开的工具提示 |
| 焦点 | 延迟后显示( 立即在热身窗口中显示) |
| 模糊 | 立即隐藏 |
Escape | 立即隐藏( 打开时只接收活动) |
可控内容 : 将指针从触发器移动到内容(反之亦然)保持了工具提示的开放. 这允许用户在工具提示中与链接或可选文本交互.
重点优先事项: 虽然触发器有键盘焦点,但即使指针离开,工具提示仍然保持开口. 这样可以防止键盘导航时的罐子关闭.
许可证
麻省理工学院