tooltip 是一个浮动元素,当它接收到键盘焦点或鼠标悬停在其上时,它会显示与锚元素相关的信息。
¥A tooltip is a floating element that displays information related to an anchor element when it receives keyboard focus or the mouse hovers over it.
基础
¥Essentials
可访问的工具提示组件具有以下品质:
¥An accessible tooltip component has the following qualities:
-
动态锚定位:工具提示位于其参考元素旁边,并保持锚定到它,同时避免冲突。
¥Dynamic anchor positioning: The tooltip is positioned next to its reference element, and remains anchored to it while avoiding collisions.
-
事件:当鼠标悬停在参考元素上或参考元素接收键盘焦点时,工具提示将打开。当鼠标离开或参考模糊时,工具提示将关闭。
¥Events: When the mouse hovers over the reference element, or when the reference element receives keyboard focus, the tooltip opens. When the mouse leaves, or the reference is blurred, the tooltip closes.
-
退出:当用户在工具提示打开时按
esc
键,它将关闭。¥Dismissal: When the user presses the
esc
key while the tooltip is open, it closes. -
角色:这些元素被赋予了相关的角色和 ARIA 属性,以便屏幕阅读器可以访问。
¥Role: The elements are given relevant role and ARIA attributes to be accessible to screen readers.
示例
¥Examples
下面有部分对这两个示例进行了深入解释。
¥Both of these examples have sections explaining them in-depth below.
基本工具提示
¥Basic tooltip
此示例演示如何创建在单个实例中使用的工具提示以熟悉基础知识。
¥This example demonstrates how to create a tooltip for use in a single instance to familiarize yourself with the fundamentals.
让我们看一下这个例子:
¥Let’s walk through the example:
打开状态
¥Open state
isOpen
确定工具提示当前是否在屏幕上打开。它用于条件渲染。
¥isOpen
determines whether or not the tooltip is
currently open on the screen. It is used for conditional
rendering.
useFloating 钩子
¥useFloating Hook
useFloating()
Hook 为我们的工具提示提供定位和上下文。我们需要向它传递一些信息:
¥The useFloating()
Hook provides positioning and context
for our tooltip. We need to pass it some information:
-
open
:上面useState()
Hook 的打开状态。¥
open
: The open state from ouruseState()
Hook above. -
onOpenChange
:打开或关闭工具提示时将调用的回调函数。我们将使用它来更新我们的isOpen
状态。¥
onOpenChange
: A callback function that will be called when the tooltip is opened or closed. We’ll use this to update ourisOpen
state. -
middleware
:导入中间件并将其传递到数组,以确保工具提示保留在屏幕上,无论它最终位于何处。¥
middleware
: Import and pass middleware to the array that ensure the tooltip remains on the screen, no matter where it ends up being positioned. -
whileElementsMounted
:仅当参考元素和浮动元素都已安装以提高性能时,才可以在必要时更新位置,确保工具提示保持锚定到参考元素。¥
whileElementsMounted
: Ensure the tooltip remains anchored to the reference element by updating the position when necessary, only while both the reference and floating elements are mounted for performance.
与钩子交互
¥Interaction Hooks
交互钩子返回包含属性键的对象,这些属性使工具提示能够打开、关闭或可供屏幕阅读器访问。
¥Interaction Hooks return objects containing keys of props that enable the tooltip to be opened, closed, or accessible to screen readers.
使用从 Hook 返回的 context
,调用交互 Hooks:
¥Using the context
that was returned from the Hook,
call the interaction Hooks:
-
useHover()
添加了当参考元素悬停在上方时打开或关闭工具提示的功能。move
选项设置为 false,以便忽略mousemove
事件。¥
useHover()
adds the ability to toggle the tooltip open or closed when the reference element is hovered over. Themove
option is set to false so thatmousemove
events are ignored. -
useFocus()
添加了当参考元素获得焦点时打开或关闭工具提示的功能。¥
useFocus()
adds the ability to toggle the tooltip open or closed when the reference element is focused. -
useDismiss()
添加了当用户按esc
键时关闭工具提示的功能。¥
useDismiss()
adds the ability to dismiss the tooltip when the user presses theesc
key. -
useRole()
将tooltip
的正确 ARIA 属性添加到工具提示和参考元素中。¥
useRole()
adds the correct ARIA attributes for atooltip
to the tooltip and reference elements.
最后,useInteractions()
将他们所有的 props 合并为可用于渲染的 prop getter。
¥Finally, useInteractions()
merges all of their props into
prop getters which can be used for rendering.
渲染
¥Rendering
现在我们已经设置了所有变量和 Hooks,我们可以渲染我们的元素。
¥Now we have all the variables and Hooks set up, we can render out our elements.
-
{...getReferenceProps()}
/{...getFloatingProps()}
将交互 Hook 中的 props 传播到相关元素上。它们包含onMouseEnter
、aria-describedby
等属性。¥
{...getReferenceProps()}
/{...getFloatingProps()}
spreads the props from the interaction Hooks onto the relevant elements. They contain props likeonMouseEnter
,aria-describedby
, etc.
可重用的工具提示组件
¥Reusable tooltip component
最好创建一个可重用的组件 API,可以更轻松地在各种不同的场景中使用。我们可以将所有 Hook 放入单个自定义 Hook 中,以获得更好的可重用性,然后由封装状态的控制器组件使用。
¥It is better to create a reusable component API that can be used in a variety of different scenarios more easily. We can place all of our Hooks into a single custom Hook for better reusability, which is then used by a controller component which encapsulates the state.
可重复使用的组件可以:
¥The reusable component can:
-
不受控制或受控制
¥Be uncontrolled or controlled
-
接受任何元素作为
<TooltipTrigger />
¥Accept any element as the
<TooltipTrigger />
-
读取打开状态改变样式
¥Read the open state to change styles
控制器组件
¥Controller component
<Tooltip />
这是控制器组件,用于管理工具提示的状态并向其余组件提供 API。
¥This is the controller component that manages the tooltip’s state and provides the API to the rest of the components.
渲染组件
¥Render components
这些组件读取根工具提示组件提供的上下文并渲染适当的元素。
¥These components read the context provided by the root Tooltip component and render the appropriate elements.
组件必须封装在 forwardRef()
中以允许引用,并且应该合并引用以确保所有引用都被保留并转发到元素。属性也被合并以防止覆盖。
¥The components must be wrapped in forwardRef()
to allow
refs, and should merge the refs to ensure all refs are preserved
and forwarded to the element. Props are also merged to prevent
overwriting.
-
<TooltipTrigger />
是工具提示所附加的触发按钮。如果你想将asChild
属性附加到自定义元素,则它接受asChild
属性。它还具有基于打开/关闭状态附加到样式的data-state
。¥
<TooltipTrigger />
is the trigger button the tooltip is attached to. This accepts anasChild
prop if you want to attach it to a custom element. It also has adata-state
attached to style based on the open/closed state. -
<TooltipContent />
是工具提示元素,它可以包含任何子元素(React 节点)。¥
<TooltipContent />
is the tooltip element, which can contain any children (React nodes).
延迟组
¥Delay groups
工具提示最有用的用户体验改进之一是使附近的工具提示共享延迟。
¥One of the most useful UX improvements for tooltips is making nearby tooltips share a delay.
禁用按钮
¥Disabled buttons
有时你想要禁用按钮,但在禁用时仍显示工具提示。
¥Sometimes you want to disable a button, but still show the tooltip while it’s disabled.
禁用带有工具提示的按钮可防止其被访问,但可以使用不同的属性来解决。这取代了 disabled
属性以允许事件触发,包括键盘访问。
¥Disabling a button with a tooltip prevents it from being accessible,
but can be worked around using a different prop. This supplants
the disabled
prop to allow events to fire, including
keyboard access.