Skip to content

feat(Scoping): use themeProvider for scoping - #1380

Draft
ragi96 wants to merge 1 commit into
mainfrom
feat-scoping-themeprovider
Draft

feat(Scoping): use themeProvider for scoping#1380
ragi96 wants to merge 1 commit into
mainfrom
feat-scoping-themeprovider

Conversation

@ragi96

@ragi96 ragi96 commented Jun 24, 2026

Copy link
Copy Markdown
Collaborator

feat(scoping): scope block CSS by marketplace app id via StyleProvider

Why

Every block scopes its generated CSS so it doesn't leak into the surrounding guideline. Until now that scope was kept in sync by hand in two disconnected places per block:

  1. a manual <div className="x-block"> wrapper in the component, and
  2. a hard-coded scope: '.x-block' in postcss.config.js.

This is fragile — glyphs-block proved it by rendering className="glyps-block" (typo) while scoping to .glyphs-block, so its scoped styles never matched the element. The class names were also arbitrary and not tied to anything canonical.

This PR makes the marketplace app id (appId from each block's manifest.json) the single source of truth for scoping, used by both the runtime class and the PostCSS build scope, and centralizes the wrapper in StyleProvider.

What changed

  • StyleProvider now owns the scope element. It renders the wrapping <div>, applies the appId as its className, and forwards ref + arbitrary DOM props (data-test-id, key, extra classes). It also passes appId to Fondue's ThemeProvider className, which propagates the scope class to portaled content (Dropdown, Tooltip, Dialog), so overlays rendered at body level are scoped natively.
  • PostCSS scope is derived from the manifest. Each block's postcss.config.js now uses scope: `.${require('./manifest.json').appId}` instead of a hard-coded class.
  • Simplified postcss/scope.js. Removed the getModalExtensions hack (the hardcoded body [data-overlay-container] / [role='dialog'] / [data-is-underlay] / [role='toolbar'] selectors) — Fondue's ThemeProvider propagation now covers portals, so a plain ${scope} ${selector} prefix suffices.
  • 20 components updated (19 blocks + the asset-upload example): the manual <div className="x-block"> wrapper is replaced by <StyleProvider appId={manifest.appId} …> with preserved props.
  • Fixes glyphs-block styling bug for free (the glyps-block typo class is gone).

Result

Generated CSS is now isolated per block, e.g. for gradient-block:

.clexy16s300010pw1gf0c4bne .tw-flex { display: flex }

Since each block has a unique appId, blocks no longer interfere with each other.

Verification

  • pnpm typecheck, pnpm lint, pnpm prettier — all clean
  • pnpm test:unit — 243 passed
  • ✅ Confirmed via the real PostCSS pipeline that rules are scoped to .<appId> with no overlay extensions
  • pnpm test:components (Cypress) not run — couldn't launch in the dev sandbox; please ensure CI runs it

Things to fix

  • RTE is currently not scoped and only works by "accident" (as it still uses old fondue components which are not relying on the themeProvider)

🤖 Generated with Claude Code

@ragi96
ragi96 requested a review from peter-tudosa June 24, 2026 09:20
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.

1 participant