Skip to content

Improve theming support when Fluent React is rendered in shadow DOM #30241

Description

Library

React Components / v9 (@fluentui/react-components)

Describe the feature that you would like added

FluentProvider provider is unaware of shadow DOM and therefore does not inject styles in a way that is 100% compatible with shadow DOM (examples below).

Currently workarounds exist for this issue but we should explore options for something like a "ShadowDomFluentProvider" to provide a simple experience for users that "just works".

Have you discussed this feature with our team

Sean Monahan (@spmonahan)

Additional context

Consider the following JSX snippet:

<shadow-dom>
  <FluentProvider theme={webLightTheme}>
     <FluentControls/>
   </FluentProvider>
</shadow-dom>

This renders the following HTML snippet:

<div>
  #shadow-root
    <div class="fui-FluentProvider fui-FluentProvider1 ...">
        <!-- ... -->
    </div>
</div>

Internally FluentProvider takes the theme prop and generates a CSS style declaration of CSS vars and inserts this style into document.head as a <style> tag. The style targets the provider by class name. That is it looks something like:

.fui-FluentProvider1 {
  --var-1 ...
}

Because a shadow boundary exists between the targeted DOM node and the style definition the styles do not apply and Fluent controls within the shadow DOM do not get access to the CSS vars despite the fact the CSS vars pierce the shadow boundary.

This can be handled in a couple ways today.

  1. Put FluentProvider in the light DOM
  2. Use createCSSRuleFromTheme() and insert the styles into the shadow DOM.

Examples of each are here: https://stackblitz.com/@spmonahan/collections/fluent-ui-react-styling-with-shadow-dom

Both of these require fairly detailed knowledge of how Fluent theming works, which is fine, but not necessarily a nice developer experience. We should consider other options to make FluentProvider "just work" with these other options as "advanced options".

With that, a couple ideas:

Make FluentProvider aware of the shadow DOM

By using Node.getRootNode() FluentProvider can know whether it is rendered within a shadow root and conditionally insert its styles into the shadow root (or use constructable stylesheets).

Discarded. See comment for details.

Make a "themeless" Provider

Similar in concept to HeadlessProvider but rather than omit a DOM element this provider will attach no styles by default, instead relying on users to provide them. FluentProvider provides more than just the theme so we'd like to continue to use these other features without the theme.

Make a simple "shadow dom aware" component for injecting styles

This would be used alongside ThemelessProvider to inject styles when necessary.

Validations

  • Check that there isn't already an issue that request the same feature to avoid creating a duplicate.

Priority

High

Metadata

Metadata

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions