Skip to content

feat: Focus Management within ShadowDOM - #6046

Merged
snowystinger merged 146 commits into
adobe:mainfrom
ritz078:shadow-dom-enhancement-1-getRootNode
Feb 6, 2025
Merged

feat: Focus Management within ShadowDOM#6046
snowystinger merged 146 commits into
adobe:mainfrom
ritz078:shadow-dom-enhancement-1-getRootNode

Conversation

@MahmoudElsayad

@MahmoudElsayad MahmoudElsayad commented Mar 11, 2024

Copy link
Copy Markdown
Contributor

Closes #1472

This PR enhances focus management capabilities in React Spectrum applications when used within Shadow DOM environments.

Changes

  • Introduced a new utility function getRootNode, designed to return a given element's contextually appropriate root (Document or ShadowRoot). This improves the library's ability to query and manipulate focus within shadow DOMs.
  • Added Shadow DOM support to the following:
    • FocusScope
    • useFocus
    • useFocusVisible
    • useFocusWithin
    • useInteractionOutside
    • usePress
  • Implemented a new utility function, getRootBody that determines the effective "body" element for an event's propagation path, supporting both Shadow DOM and traditional document structures.
  • implemented a new utility, ' getDeepActiveElement,` which retrieves the currently focused element across Shadow DOM boundaries, ensuring accurate focus management in complex DOM structures.
  • Added tests for all new utility functions and affected hooks/components.

✅ Pull Request Checklist:

  • Included link to corresponding React Spectrum GitHub Issue.
  • Added/updated unit tests and storybook for this change (for new code or code which already has tests).
  • Filled out test instructions.
  • Updated documentation (if it already exists for this component).
  • Looked at the Accessibility Practices for this feature - Aria Practices

📝 Test Instructions:

  • Open any storybook example that uses any of the affected hooks/components
  • Test the functionality and make sure it works when the story is encapsulated inside a shadow root.
// custom wrapper to run any story inside a shadow root
function ShadowDomWrapper({ children }) {
  const container = useRef(null);

  useEffect(() => {
    const _container = container.current;
    if (!_container) return;

    const div = document.createElement('div');
    _container.appendChild(div);

    const shadowRoot = div.attachShadow({ mode: 'open' });
    const main = document.createElement('main');
    shadowRoot.appendChild(main);

    // Wrap children with the ThemeProvider when rendering
    ReactDOM.render(
      children,
      main
    );

    return () => {
      ReactDOM.unmountComponentAtNode(main);
      if (_container) {
        _container.innerHTML = '';
      }
    };
  }, [children]);

  return <div ref={container} />;
}
// .storybook/preview.js
export const decorators = [
+    (Story) => (
+     <ShadowDomWrapper>
+        <Story />
+      </ShadowDomWrapper>
+    ),
  withScrollingSwitcher,
  ...(process.env.NODE_ENV !== 'production' ? [withStrictModeSwitcher] : []),
  withProviderSwitcher
];

🧢 Your Project:

PSPDFKit -

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

FocusScope not working when used inside shadowRoot

10 participants