Skip to content

Commit

Permalink
Fix focus manager for React 16
Browse files Browse the repository at this point in the history
React 17 switched to using `focusin`/`focusout` events for
`onFocus`/`onBlur` [1]. floating-ui's focus manager appears to depend
on this implicitly, causing focus to revert to body when tab-ing back
into a floating portal with Reacht 16.

Manually using `focusin`/`focusout` appears to fix the problem.

[1] facebook/react#19186
  • Loading branch information
tf committed Jul 23, 2024
1 parent fe06ea2 commit f387355
Show file tree
Hide file tree
Showing 2 changed files with 12,304 additions and 10,185 deletions.
19 changes: 16 additions & 3 deletions packages/react/src/components/FocusGuard.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {isSafari} from '@floating-ui/react/utils';
import { isSafari } from '@floating-ui/react/utils';
import * as React from 'react';
import useModernLayoutEffect from 'use-isomorphic-layout-effect';

import {createAttribute} from '../utils/createAttribute';
import { createAttribute } from '../utils/createAttribute';

// See Diego Haz's Sandbox for making this logic work well on Safari/iOS:
// https://codesandbox.io/s/tabbable-portal-f4tng?file=/src/FocusTrap.tsx
Expand Down Expand Up @@ -33,7 +33,7 @@ function setActiveElementOnTab(event: KeyboardEvent) {

export const FocusGuard = React.forwardRef(function FocusGuard(
props: React.ComponentPropsWithoutRef<'span'>,
ref: React.ForwardedRef<HTMLSpanElement>,
ref: React.ForwardedRef<HTMLSpanElement>
) {
const [role, setRole] = React.useState<'button' | undefined>();

Expand All @@ -48,8 +48,20 @@ export const FocusGuard = React.forwardRef(function FocusGuard(
}

document.addEventListener('keydown', setActiveElementOnTab);

let current: HTMLSpanElement;

if (ref && 'current' in ref && ref.current) {
current = ref.current;
current.addEventListener('focusin', props.onFocus);
}

return () => {
document.removeEventListener('keydown', setActiveElementOnTab);

if (current) {
current.removeEventListener('focusin', props.onFocus);
}
};
}, []);

Expand All @@ -61,6 +73,7 @@ export const FocusGuard = React.forwardRef(function FocusGuard(
'aria-hidden': role ? undefined : true,
[createAttribute('focus-guard')]: '',
style: HIDDEN_STYLES,
onFocus: null,
};

return <span {...props} {...restProps} />;
Expand Down
Loading

0 comments on commit f387355

Please sign in to comment.