Skip to content

Commit f387355

Browse files
committed
Fix focus manager for React 16
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
1 parent fe06ea2 commit f387355

File tree

2 files changed

+12304
-10185
lines changed

2 files changed

+12304
-10185
lines changed

packages/react/src/components/FocusGuard.tsx

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import {isSafari} from '@floating-ui/react/utils';
1+
import { isSafari } from '@floating-ui/react/utils';
22
import * as React from 'react';
33
import useModernLayoutEffect from 'use-isomorphic-layout-effect';
44

5-
import {createAttribute} from '../utils/createAttribute';
5+
import { createAttribute } from '../utils/createAttribute';
66

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

3434
export const FocusGuard = React.forwardRef(function FocusGuard(
3535
props: React.ComponentPropsWithoutRef<'span'>,
36-
ref: React.ForwardedRef<HTMLSpanElement>,
36+
ref: React.ForwardedRef<HTMLSpanElement>
3737
) {
3838
const [role, setRole] = React.useState<'button' | undefined>();
3939

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

5050
document.addEventListener('keydown', setActiveElementOnTab);
51+
52+
let current: HTMLSpanElement;
53+
54+
if (ref && 'current' in ref && ref.current) {
55+
current = ref.current;
56+
current.addEventListener('focusin', props.onFocus);
57+
}
58+
5159
return () => {
5260
document.removeEventListener('keydown', setActiveElementOnTab);
61+
62+
if (current) {
63+
current.removeEventListener('focusin', props.onFocus);
64+
}
5365
};
5466
}, []);
5567

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

6679
return <span {...props} {...restProps} />;

0 commit comments

Comments
 (0)