From 9c573d731b2c36a2f6fb753156467ab90c02b843 Mon Sep 17 00:00:00 2001 From: PaulGMardling Date: Tue, 8 Sep 2026 16:09:56 +0200 Subject: [PATCH 1/3] fix(react-provider): validate serialized theme tokens Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .../src/Concepts/Theming.mdx | 4 + .../createCSSRuleFromThemeDescription.md | 4 + ...-8f64011f-66bb-4fae-bf5e-e52d91e39408.json | 7 + .../contributing/patterns/extending-tokens.md | 3 + .../FluentProvider-node.test.tsx | 25 ++ .../FluentProvider/FluentProvider.types.ts | 7 +- .../createCSSRuleFromTheme.test.ts | 107 ++++++ .../FluentProvider/createCSSRuleFromTheme.ts | 330 +++++++++++++++++- .../useFluentProviderThemeStyleTag.test.tsx | 21 ++ 9 files changed, 506 insertions(+), 2 deletions(-) create mode 100644 change/@fluentui-react-provider-8f64011f-66bb-4fae-bf5e-e52d91e39408.json diff --git a/apps/public-docsite-v9/src/Concepts/Theming.mdx b/apps/public-docsite-v9/src/Concepts/Theming.mdx index 0b116fa1418cc..446b7c2644a76 100644 --- a/apps/public-docsite-v9/src/Concepts/Theming.mdx +++ b/apps/public-docsite-v9/src/Concepts/Theming.mdx @@ -112,6 +112,10 @@ export const customDarkTheme = createDarkTheme(customBrandRamp); A theme is a flat object containing `{ [token name]: CSS value }` pairs. You can copy the object and overwrite any tokens you wish. +Theme names and values are developer-authored CSS. If theme customization is based on dynamic data, validate it against +an application-specific schema before constructing the theme. Fluent UI contains generated declarations structurally, +but does not determine whether a valid CSS value or URL is appropriate for your application. + ```tsx import { webLightTheme, Theme } from '@fluentui/react-components'; diff --git a/apps/public-docsite-v9/src/Utilities/Theme/createCSSRuleFromTheme/createCSSRuleFromThemeDescription.md b/apps/public-docsite-v9/src/Utilities/Theme/createCSSRuleFromTheme/createCSSRuleFromThemeDescription.md index 2d6e57860012b..dc977f1871e2f 100644 --- a/apps/public-docsite-v9/src/Utilities/Theme/createCSSRuleFromTheme/createCSSRuleFromThemeDescription.md +++ b/apps/public-docsite-v9/src/Utilities/Theme/createCSSRuleFromTheme/createCSSRuleFromThemeDescription.md @@ -1 +1,5 @@ This API allows you to create CSS from a theme and apply this CSS, for example, to ``. + +The selector and theme are developer-authored CSS. Validate dynamic data against an application-specific schema before +using it to construct a theme. The generated declarations are structurally contained, but the API does not determine +whether a valid CSS value or URL is appropriate for your application. diff --git a/change/@fluentui-react-provider-8f64011f-66bb-4fae-bf5e-e52d91e39408.json b/change/@fluentui-react-provider-8f64011f-66bb-4fae-bf5e-e52d91e39408.json new file mode 100644 index 0000000000000..ed3af4a6b461b --- /dev/null +++ b/change/@fluentui-react-provider-8f64011f-66bb-4fae-bf5e-e52d91e39408.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "fix: structurally validate serialized theme tokens", + "packageName": "@fluentui/react-provider", + "email": "paulmardling@microsoft.com", + "dependentChangeType": "patch" +} diff --git a/docs/react-v9/contributing/patterns/extending-tokens.md b/docs/react-v9/contributing/patterns/extending-tokens.md index f26008de479f0..1fc1e94679843 100644 --- a/docs/react-v9/contributing/patterns/extending-tokens.md +++ b/docs/react-v9/contributing/patterns/extending-tokens.md @@ -4,6 +4,9 @@ It's often useful for an app to extend the base set of tokens from Fluent UI. ⚠ Warning that adding more tokens adds more CSS variables which can effect run time performance as each DOM Node carries all the tokens. +Theme names and values are developer-authored CSS. Validate dynamic data against an application-specific schema before +using it to construct or extend a theme. + ```tsx import { makeStyles, themeToTokensObject, webLightTheme, FluentProvider, Theme } from '@fluentui/react-components'; diff --git a/packages/react-components/react-provider/library/src/components/FluentProvider/FluentProvider-node.test.tsx b/packages/react-components/react-provider/library/src/components/FluentProvider/FluentProvider-node.test.tsx index 3bca12bf969f9..f989b31b353eb 100644 --- a/packages/react-components/react-provider/library/src/components/FluentProvider/FluentProvider-node.test.tsx +++ b/packages/react-components/react-provider/library/src/components/FluentProvider/FluentProvider-node.test.tsx @@ -76,4 +76,29 @@ describe('FluentProvider (node)', () => { " `); }); + + it('omits invalid theme entries from the server style element', () => { + const logWarnSpy = jest.spyOn(console, 'warn').mockImplementation(() => undefined); + const theme = { + invalidToken: 'url(resource/*);token/**/)', + validToken: 'green', + } as unknown as PartialTheme; + + const html = renderToStaticMarkup(); + + expect(parseHTMLString(html)).toMatchInlineSnapshot(` + "
+ +
" + `); + expect(html.match(/ " `); expect(html.match(/