Skip to content

Docs: Make CSS ordering in DocsContainer more predictable#34015

Merged
Sidnioulz merged 2 commits intonextfrom
copilot/fix-dynamic-theme-styles
Mar 11, 2026
Merged

Docs: Make CSS ordering in DocsContainer more predictable#34015
Sidnioulz merged 2 commits intonextfrom
copilot/fix-dynamic-theme-styles

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 4, 2026

Manual testing

Setup

  1. Make a fresh sandbox
  2. Copy the logic in the .storybook/preview of https://stackblitz.com/edit/vitejs-vite-yow74x into your sandbox
  3. Adjust context.store.globals.globals to context.store.userGlobals.globals
  4. Run storybook
  5. Continue with OG repro under

Original repro steps

  1. Open the test story (in a new tab, not within the stackblitz UI)
  2. Change the theme from light to dark (using the toolbar theme switcher)
  3. You'll see the left margin incorrectly change on header
  4. Refresh, and the theme should stay dark but with the correct left margin
  5. Change from dark to light (using the toolbar theme switcher)
  6. You'll see the left margin incorrectly change on header

Dynamically changing the theme passed to DocsContainer causes style breakage (e.g., incorrect margins on headers) because Emotion's CSS class insertion order becomes unpredictable across theme switches.

Root cause

styled() with multiple arguments (e.g., styled.h1(withReset, headerCommon, themeFunc)) generates a separate CSS class per argument. On theme change, arguments with unchanged output (like withReset, which only references fonts/sizes constant across themes) reuse their cached class at its original stylesheet position, while arguments with changed output (like headerCommon, which references theme.color.defaultText) get new classes appended at the end. Since DocsContent's :where() selectors and component classes share specificity 0-1-0, cascade order determines which wins — and that order just shifted.

Fix

Merge all styled() arguments into a single function per component so each produces exactly one CSS class, always regenerated atomically on theme change:

// Before: 3 classes, independently cached → ordering drift on theme change
export const H1 = styled.h1(withReset, headerCommon, ({ theme }) => ({
  fontSize: `${theme.typography.size.l1}px`,
  fontWeight: theme.typography.weight.bold,
}));

// After: 1 class, always regenerated together → stable ordering
export const H1 = styled.h1(({ theme }) => ({
  ...(withReset({ theme }) as CSSObject),
  ...(headerCommon({ theme }) as CSSObject),
  fontSize: `${theme.typography.size.l1}px`,
  fontWeight: theme.typography.weight.bold,
}));
  • Core typography elements (H1–H6, A, Blockquote, Code, DL, LI, OL, P, Pre, Span, Table, UL): merged withReset, headerCommon, withMargin, codeCommon into single theme functions
  • Docs components (DocsPage Title/Subtitle, Title): same treatment

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

… CSS ordering on theme change

When styled() is called with multiple arguments (e.g., styled.h1(withReset, headerCommon, themeFunc)),
Emotion generates separate CSS classes for each argument. On theme change, unchanged classes are reused
at their original stylesheet position while changed ones are appended at the end. This causes
unpredictable CSS cascade ordering since DocsContent's :where() selectors and component classes share
the same specificity (0-1-0).

By merging all arguments into a single function, each component produces exactly one CSS class that is
always regenerated together on theme change, ensuring consistent stylesheet ordering.

Co-authored-by: Sidnioulz <5108577+Sidnioulz@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix dynamic theme causing style issues in DocsContainer Fix CSS ordering instability when DocsContainer theme changes dynamically Mar 4, 2026
@nx-cloud
Copy link
Copy Markdown

nx-cloud bot commented Mar 5, 2026

View your CI Pipeline Execution ↗ for commit 8fcdfe9

Command Status Duration Result
nx run-many -t compile,check,knip,test,pretty-d... ❌ Failed 13m 47s View ↗

☁️ Nx Cloud last updated this comment at 2026-03-05 09:13:28 UTC

@Sidnioulz Sidnioulz changed the title Fix CSS ordering instability when DocsContainer theme changes dynamically Docs: Make CSS ordering in DocsContainer more predictable Mar 5, 2026
@Sidnioulz
Copy link
Copy Markdown
Member

@yannbf I think we did something else since SB 8 that causes docs to reload entirely when the theme switches. That reload causes classes to load with correct ordering and fixes the reported bug.

This being said, I see no significant difference in built bundle size between this PR and next, and I think Claude's reasoning is correct. Merging this PR should make our class names more robust to ordering problems as we would stop partially regenerating a given component's CSS.

If you also think this is sound reasoning, and if CI is green, I'd like to merge this.

@Sidnioulz Sidnioulz marked this pull request as ready for review March 5, 2026 09:04
@Sidnioulz Sidnioulz requested review from Sidnioulz and yannbf March 5, 2026 09:04
Copy link
Copy Markdown
Member

@Sidnioulz Sidnioulz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code LGTM (pending CI/CH outputs)

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 5, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c3a599e2-643a-4364-8328-feba971af05d

📥 Commits

Reviewing files that changed from the base of the PR and between 670866d and 8fcdfe9.

📒 Files selected for processing (19)
  • code/addons/docs/src/blocks/components/DocsPage.tsx
  • code/addons/docs/src/blocks/components/Title.tsx
  • code/core/src/components/components/typography/elements/A.tsx
  • code/core/src/components/components/typography/elements/Blockquote.tsx
  • code/core/src/components/components/typography/elements/Code.tsx
  • code/core/src/components/components/typography/elements/DL.tsx
  • code/core/src/components/components/typography/elements/H1.tsx
  • code/core/src/components/components/typography/elements/H2.tsx
  • code/core/src/components/components/typography/elements/H3.tsx
  • code/core/src/components/components/typography/elements/H4.tsx
  • code/core/src/components/components/typography/elements/H5.tsx
  • code/core/src/components/components/typography/elements/H6.tsx
  • code/core/src/components/components/typography/elements/LI.tsx
  • code/core/src/components/components/typography/elements/OL.tsx
  • code/core/src/components/components/typography/elements/P.tsx
  • code/core/src/components/components/typography/elements/Pre.tsx
  • code/core/src/components/components/typography/elements/Span.tsx
  • code/core/src/components/components/typography/elements/Table.tsx
  • code/core/src/components/components/typography/elements/UL.tsx

📝 Walkthrough

Walkthrough

This PR systematically refactors styled-component invocations across 19 files, changing the style composition pattern from passing helper functions as separate arguments to inlining them via object spreads within theme-aware functions. Type imports are updated to use CSSObject with explicit type casts.

Changes

Cohort / File(s) Summary
Docs Components
code/addons/docs/src/blocks/components/DocsPage.tsx, code/addons/docs/src/blocks/components/Title.tsx
Title and Subtitle components refactored to compose withReset via object spread with CSSObject typing instead of separate argument to styled components.
Header Elements (H1–H6)
code/core/src/components/components/typography/elements/H[1-6].tsx
All header elements updated to inline withReset and headerCommon helpers within theme-aware style functions via object spreads and CSSObject casts, removing them from separate arguments.
Text Block Elements
code/core/src/components/components/typography/elements/P.tsx, code/core/src/components/components/typography/elements/Pre.tsx, code/core/src/components/components/typography/elements/Blockquote.tsx, code/core/src/components/components/typography/elements/Span.tsx, code/core/src/components/components/typography/elements/Table.tsx
Paragraph, pre, blockquote, span, and table elements refactored to merge withReset and withMargin helpers within theme-aware style callbacks via object spreads instead of separate arguments.
Code Element
code/core/src/components/components/typography/elements/Code.tsx
DefaultCodeBlock styling updated to merge codeCommon helper into style object via spread with CSSObject cast instead of second argument.
List Elements
code/core/src/components/components/typography/elements/[OL,UL,LI,DL].tsx
Ordered list, unordered list, list item, and definition list components refactored to compose withReset, withMargin, and listCommon helpers within theme-aware callbacks; Interpolation type replaced with CSSObject in OL and UL.
Link Element
code/core/src/components/components/typography/elements/A.tsx
A component refactored to compose withReset within theme-aware style function via object spread and CSSObject cast instead of separate argument.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)

Comment @coderabbitai help to get the list of available commands and usage tips.

@Sidnioulz
Copy link
Copy Markdown
Member

Fails
🚫 The "#### Manual testing" section must be filled in. Please describe how to test the changes you've made, step by step, so that reviewers can confirm your PR works as intended.
Generated by 🚫 dangerJS against 8fcdfe9

@copilot adjust the PR description

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 6, 2026

Fails
🚫 The "#### Manual testing" section must be filled in. Please describe how to test the changes you've made, step by step, so that reviewers can confirm your PR works as intended.
Gene...

Updated the PR description to include the "#### Manual testing" section with setup and reproduction steps.

@Sidnioulz Sidnioulz merged commit cfe3df5 into next Mar 11, 2026
131 of 142 checks passed
@Sidnioulz Sidnioulz deleted the copilot/fix-dynamic-theme-styles branch March 11, 2026 11:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants