Skip to content

Commit 024a2f7

Browse files
committed
feat(focus-scope): use get-deep-active-element to cross the shadow DOM boundary
1 parent f23d14c commit 024a2f7

File tree

3 files changed

+46
-7
lines changed

3 files changed

+46
-7
lines changed

packages/react/focus-scope/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
"build": "radix-build"
3535
},
3636
"dependencies": {
37+
"@radix-ui/deep-active-element": "workspace:*",
3738
"@radix-ui/react-compose-refs": "workspace:*",
3839
"@radix-ui/react-primitive": "workspace:*",
3940
"@radix-ui/react-use-callback-ref": "workspace:*"

packages/react/focus-scope/src/focus-scope.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as React from 'react';
22
import { useComposedRefs } from '@radix-ui/react-compose-refs';
33
import { Primitive } from '@radix-ui/react-primitive';
44
import { useCallbackRef } from '@radix-ui/react-use-callback-ref';
5+
import { getDeepActiveElement } from '@radix-ui/deep-active-element'
56

67
const AUTOFOCUS_ON_MOUNT = 'focusScope.autoFocusOnMount';
78
const AUTOFOCUS_ON_UNMOUNT = 'focusScope.autoFocusOnUnmount';
@@ -109,7 +110,7 @@ const FocusScope = React.forwardRef<FocusScopeElement, FocusScopeProps>((props,
109110
// back to the document.body. In this case, we move focus to the container
110111
// to keep focus trapped correctly.
111112
function handleMutations(mutations: MutationRecord[]) {
112-
const focusedElement = document.activeElement as HTMLElement | null;
113+
const focusedElement = getDeepActiveElement() as HTMLElement | null;
113114
if (focusedElement !== document.body) return;
114115
for (const mutation of mutations) {
115116
if (mutation.removedNodes.length > 0) focus(container);
@@ -132,7 +133,7 @@ const FocusScope = React.forwardRef<FocusScopeElement, FocusScopeProps>((props,
132133
React.useEffect(() => {
133134
if (container) {
134135
focusScopesStack.add(focusScope);
135-
const previouslyFocusedElement = document.activeElement as HTMLElement | null;
136+
const previouslyFocusedElement = getDeepActiveElement() as HTMLElement | null;
136137
const hasFocusedCandidate = container.contains(previouslyFocusedElement);
137138

138139
if (!hasFocusedCandidate) {
@@ -141,7 +142,7 @@ const FocusScope = React.forwardRef<FocusScopeElement, FocusScopeProps>((props,
141142
container.dispatchEvent(mountEvent);
142143
if (!mountEvent.defaultPrevented) {
143144
focusFirst(removeLinks(getTabbableCandidates(container)), { select: true });
144-
if (document.activeElement === previouslyFocusedElement) {
145+
if (getDeepActiveElement() === previouslyFocusedElement) {
145146
focus(container);
146147
}
147148
}
@@ -176,7 +177,7 @@ const FocusScope = React.forwardRef<FocusScopeElement, FocusScopeProps>((props,
176177
if (focusScope.paused) return;
177178

178179
const isTabKey = event.key === 'Tab' && !event.altKey && !event.ctrlKey && !event.metaKey;
179-
const focusedElement = document.activeElement as HTMLElement | null;
180+
const focusedElement = getDeepActiveElement() as HTMLElement | null;
180181

181182
if (isTabKey && focusedElement) {
182183
const container = event.currentTarget as HTMLElement;
@@ -216,10 +217,10 @@ FocusScope.displayName = FOCUS_SCOPE_NAME;
216217
* Stops when focus has actually moved.
217218
*/
218219
function focusFirst(candidates: HTMLElement[], { select = false } = {}) {
219-
const previouslyFocusedElement = document.activeElement;
220+
const previouslyFocusedElement = getDeepActiveElement();
220221
for (const candidate of candidates) {
221222
focus(candidate, { select });
222-
if (document.activeElement !== previouslyFocusedElement) return;
223+
if (getDeepActiveElement() !== previouslyFocusedElement) return;
223224
}
224225
}
225226

@@ -290,7 +291,7 @@ function isSelectableInput(element: any): element is FocusableTarget & { select:
290291
function focus(element?: FocusableTarget | null, { select = false } = {}) {
291292
// only focus if that element is focusable
292293
if (element && element.focus) {
293-
const previouslyFocusedElement = document.activeElement;
294+
const previouslyFocusedElement = getDeepActiveElement();
294295
// NOTE: we prevent scrolling on focus, to minimize jarring transitions for users
295296
element.focus({ preventScroll: true });
296297
// only select if its not the same element, it supports selection and we need to select

pnpm-lock.yaml

Lines changed: 37 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)