Skip to content

FloatingFocusManager

为浮动元素提供灵活的模态或非模态焦点管理。模态行为是默认的 - 渲染时焦点完全被捕获在浮动元素内。

¥Provides flexible modal or non-modal focus management for a floating element. Modal behavior is the default — focus is fully trapped inside the floating element while it is rendered.

import {FloatingFocusManager} from '@floating-ui/react';

这对于确保正确管理键盘交互的焦点是必要的。

¥This is necessary to ensure that focus is properly managed for keyboard interaction.

该组件仅应在浮动元素打开并直接封装它时渲染。

¥This component should only be rendered when the floating element is open and directly wrap it.

function App() {
  const {context} = useFloating();
 
  return (
    <>
      {/* reference element */}
      {isOpen && (
        <FloatingFocusManager context={context}>
          {/* floating element */}
        </FloatingFocusManager>
      )}
    </>
  );
}

属性

¥Props

interface FloatingFocusManagerProps {
  context: FloatingContext;
  disabled?: boolean;
  initialFocus?:
    | number
    | React.MutableRefObject<HTMLElement | null>;
  returnFocus?: boolean;
  restoreFocus?: boolean;
  guards?: boolean;
  modal?: boolean;
  visuallyHiddenDismiss?: boolean | string;
  closeOnFocusOut?: boolean;
  order?: Array<'reference' | 'floating' | 'content'>;
}

context

Required

useFloating() 返回的 context 对象。

¥The context object returned from useFloating().

<FloatingFocusManager context={context}>
  {/* floating element */}
</FloatingFocusManager>

disabled

默认:false

¥default: false

完全禁用所有焦点管理。用于延迟焦点管理,直到转换完成或某些其他条件状态之后。

¥Disables all focus management entirely. Useful to delay focus management until after a transition completes or some other conditional state.

<FloatingFocusManager context={context} disabled>
  {/* floating element */}
</FloatingFocusManager>

initialFocus

默认:0

¥default: 0

最初关注哪个元素。可以是数字(由 order 指定的可选项索引)或引用。

¥Which element to initially focus. Can be either a number (tabbable index as specified by the order) or a ref.

<FloatingFocusManager
  context={context}
  initialFocus={elementRef}
>
  {/* floating element */}
</FloatingFocusManager>

负数

¥Negative number

你可以将其设置为负数以忽略初始焦点。如果你的浮动元素没有可选项内容,而是由具有自己的焦点管理的 useListNavigation() Hook 控制,则需要这样做以防止冲突。

¥You can set this to a negative number to ignore the initial focus. This is required to prevent conflicts if your floating element has no tabbable content and is instead controlled by the useListNavigation() Hook which has its own focus management.

<FloatingFocusManager context={context} initialFocus={-1}>
  {/* floating element */}
</FloatingFocusManager>

如果没有列表导航,那么 modal 行为的焦点陷阱将不再起作用。要保持陷阱,你可以将初始焦点放在浮动元素上:

¥If there is no list navigation, then modal behavior’s focus trap will no longer work. To maintain the trap, you can place the initial focus on the floating element:

const {context, refs} = useFloating();
 
return (
  <FloatingFocusManager
    context={context}
    initialFocus={refs.floating}
  >
    {/* floating element */}
  </FloatingFocusManager>
);

returnFocus

默认:true

¥default: true

确定焦点是否应返回到参考元素(或者如果不可用,则返回到先前获得焦点的元素)。如果浮动元素失去焦点,则忽略此属性。

¥Determines if focus should be returned to the reference element (or if that is not available, the previously focused element). This prop is ignored if the floating element lost focus.

<FloatingFocusManager context={context} returnFocus={false}>
  {/* floating element */}
</FloatingFocusManager>

restoreFocus

默认:false

¥default: false

如果浮动元素内当前聚焦的元素已从 DOM 中移除(否则会导致焦点丢失),则确定是否应将焦点恢复到最近的可制表元素。

¥Determines if focus should be restored to the nearest tabbable element if the currently focused element inside the floating element was removed from the DOM (causing focus to be lost otherwise).

<FloatingFocusManager context={context} restoreFocus={true}>
  {/* floating element */}
</FloatingFocusManager>

guards

默认:true

¥default: true

确定是否渲染焦点防护。如果没有,焦点可能会转移到地址栏/控制台/浏览器 UI,就像在原生对话框中一样。

¥Determines if the focus guards are rendered. If not, focus can escape into the address bar/console/browser UI, like in native dialogs.

<FloatingFocusManager context={context} guards={false}>
  {/* floating element */}
</FloatingFocusManager>

默认:true

¥default: true

确定焦点是否为 “modal”,这意味着焦点完全被捕获在浮动元素内,并且无法访问外部内容。这包括屏幕阅读器虚拟光标。

¥Determines if focus is “modal”, meaning focus is fully trapped inside the floating element and outside content cannot be accessed. This includes screen reader virtual cursors.

<FloatingFocusManager context={context} modal={false}>
  {/* floating element */}
</FloatingFocusManager>

非模态行为

¥Non-modal behavior

浮动元素应该在 React 树中的引用元素之后渲染。它可以使用 <FloatingPortal> 进行门户化。使用 Floating UI 的焦点管理器时,其他门户解决方案不受支持或无法访问。

¥The floating element should be rendered after the reference element in the React tree. It can be portaled using <FloatingPortal>. Other portal solutions are not supported or accessible when using Floating UI’s focus manager.

模态行为

¥Modal behavior

确保你有明确的 “close” 按钮。这可以对所有用户可见,也可以在视觉上隐藏,因此仅适用于辅助技术(参见 visuallyHiddenDismiss)。基于触摸的屏幕阅读器通常没有可用于关闭元素的 esc 键,因此需要显式关闭按钮,否则如果用户不想选择任何内容(因此需要重新加载),他们将被困在浮动元素中 这一页)。

¥Ensure you have an explicit “close” button. This can be either visible to all users, or visually-hidden so it is only available to assistive tech (see visuallyHiddenDismiss). Touch-based screen readers often will not have an esc key available to dismiss the element, so an explicit close button is required, otherwise the user will be trapped in the floating element if they don’t want to select anything (thus needing to reload the page).

组合框

¥Comboboxes

当参考元素存在 combobox role 时,焦点管理器行为会发生变化。

¥When the reference element has a combobox role present, the focus manager behavior changes.

使用模态焦点管理时,组合框(输入 + 列表框弹出窗口)的列表框部分(浮动元素)可以门户化并可供触摸屏阅读器访问,但 DOM 焦点不会变成模态。屏幕阅读器虚拟光标确实会变成模态,从而允许触摸屏阅读器立即访问门户列表框项。

¥The listbox part (floating element) of a combobox (input + listbox popup) can be portaled and accessible to touch screen readers when using modal focus management, but DOM focus does not become modal. Screen reader virtual cursors do become modal, allowing a touch screen reader to immediately access the portaled listbox items.

visuallyHiddenDismiss

默认:false

¥default: false

如果你的焦点管理是模态的并且没有可用的显式关闭按钮,则可以使用此属性在浮动元素的开头和结尾处渲染视觉上隐藏的关闭按钮。这使得基于触摸的屏幕阅读器能够摆脱由于缺少 esc 键而出现的浮动元素。

¥If your focus management is modal and there is no explicit close button available, you can use this prop to render a visually-hidden dismiss button at the start and end of the floating element. This allows touch-based screen readers to escape the floating element due to lack of an esc key.

<FloatingFocusManager context={context} visuallyHiddenDismiss>
  {/* floating element */}
</FloatingFocusManager>

你可以传递一个由屏幕阅读器宣布的字符串,例如 对于英语以外的语言。使用 true 时的默认字符串是 Dismiss

¥You can pass a string which will be announced by the screen reader, e.g. for languages other than English. The default string when using true is Dismiss.

<FloatingFocusManager
  context={context}
  visuallyHiddenDismiss="Dismiss popup"
>
  {/* floating element */}
</FloatingFocusManager>

closeOnFocusOut

默认:true

¥default: true

确定 focusout 事件监听器(控制焦点移动到浮动元素之外时是否应关闭浮动元素)是否附加到引用元素和浮动元素。这会影响非模态焦点管理。

¥Determines whether focusout event listeners that control whether the floating element should be closed if the focus moves outside of it are attached to the reference and floating elements. This affects non-modal focus management.

<FloatingFocusManager context={context} closeOnFocusOut={false}>
  {/* floating element */}
</FloatingFocusManager>

order

默认:['content']

¥default: ['content']

焦点循环的顺序。

¥The order in which focus cycles.

<FloatingFocusManager
  context={context}
  // Initially focuses the floating element. Subsequent tabs
  // will cycle through the tabbable contents of the floating
  // element.
  order={['floating', 'content']}
  // Keeps focus on the reference element. Subsequent tabs
  // will cycle through the tabbable contents of the floating
  // element.
  order={['reference', 'content']}
>
  {/* floating element */}
</FloatingFocusManager>

故障排除

¥Troubleshooting

打开浮动元素时页面滚动到顶部

¥Page scrolls to top when opening the floating element

如果你将 autoFocus 属性放置在浮动元素内的元素上,则可能会发生这种情况。这是因为浮动元素最初渲染在页面的左上角,并且浏览器在接收焦点时滚动到该元素。

¥This can happen if you’re placing the autoFocus prop on an element inside the floating element. This is because the floating element is initially rendered at the top-left of the page, and the browser scrolls to it when it receives focus.

相反,使用 <FloatingFocusManager> 上的 initialFocus 属性来聚焦所需的元素,该元素首先等待位置准备好。

¥Instead, use the initialFocus prop on <FloatingFocusManager> to focus the desired element, which waits for the position to be ready first.

<FloatingPortal> 一起使用

¥Usage with <FloatingPortal>

确保焦点管理器渲染为 <FloatingPortal> 的子级(可以是嵌套后代)。

¥Ensure the focus manager is rendered as a child (can be a nested descendant) of <FloatingPortal>.

如果你使用的是非模态焦点管理,则必须使用 <FloatingPortal>,而不是其他门户解决方案。这是因为它与焦点管理器紧密集成,以确保在制表时正确移动焦点,包括 VoiceOver 虚拟光标。

¥If you’re using non-modal focus management, you must use <FloatingPortal> and not another portal solution. This is because it tightly integrates with the focus manager to ensure that focus is moved correctly when tabbing, including the VoiceOver virtual cursor.