Skip to content

Move the Tailwind reset out of the top cascade layer in the CMS UI (#199 A1) - #203

Open
sneridagh wants to merge 4 commits into
mainfrom
a1-css-layer-order
Open

sneridagh wants to merge 4 commits into
mainfrom
a1-css-layer-order

Conversation

@sneridagh

@sneridagh sneridagh commented Oct 2, 2026 •

Copy link
Copy Markdown
Member

Step A1 of #199: the Tailwind reset in the CMS UI moves out of the top cascade layer, and the plone-content layer for block content CSS is added.

Changes

  • @plone/cmsui (styles/cmsui.css): the @layer cmsui { … } wrapper is dropped, and Tailwind is loaded with a plain @import 'tailwindcss', as @plone/theming/styles/tailwind.css already does for Agave. Tailwind's parts now land in the declared layers:

    Part Before After
    theme variables cmsui theme
    preflight (reset) cmsui, the top layer base
    utilities cmsui utilities
    @plone/components basic theme cmsui theme (@import … layer(theme))
    :root / .dark tokens cmsui theme

    @theme, @plugin, @source and @custom-variant stay top-level.

  • @plone/cmsui (index.ts): no longer appends cmsui to config.settings.cssLayers.

  • @plone/theming (index.ts): adds plone-content to the default layer order, with a comment describing it. The new order is:

    theme, base, components, plone-components, plone-content, utilities, custom
    
  • @plone/components (Table.quanta.tsx): the quanta table row's drag handle now resets the basic button styles itself (padding, border, radius, background, color, font) with utilities. Before this PR, it only looked right because the reset sat in the top layer and beat @plone/components' basic .react-aria-Button styles, which the contents view loads. This was the only regression the move caused; the A0 contents listing screenshot caught it.

Visual result

All 20 visual regression tests (native blocks, editor overlays, CMS chrome, contents listing, site frame) are pixel-identical to the screenshots taken on main before this change. I compared locally with CI=1 --retries=0 against reference screenshots generated from the pre-change build. Before the drag-handle fix, only the contents listing differed.

To confirm in CI, run the "Visual Regression Tests" workflow on this branch. It's read-only and compares against the baselines from #202's update run. It should be green.

Not changed (from the A0 inventory)

  • Shared-chunk CSS in @layer custom (@plone/layout header/navigation CSS Modules) now sits above Tailwind utilities on CMS routes. It only targets hashed classes of public header components, and the chrome screenshots show no effect.
  • Unlayered CSS (Sonner's injected styles, quanta.css's body/:root on /@@contents, the public :root tokens and heading typography, .block-inner-container, the Maps and Toolbar CSS Modules) still wins over every layer, as before. A3 and Track B deal with the parts that touch block content.

Breaking

Add-ons that put CSS in @layer cmsui get a layer that's no longer declared. It's appended after all declared layers, so it still wins, but by accident. Such add-ons should move their CSS into one of the declared layers, usually custom. The @plone/cmsui news fragment calls this out.

Validation

  • CI=1 pnpm visual-test --retries=0: 20 passed, pixel-exact against the pre-change reference.
  • pnpm acceptance-test: 164 passed.
  • pnpm --filter @plone/cmsui test --run: 189 passed. pnpm --filter @plone/components test --run: 14 passed.
  • check:ts for @plone/cmsui, @plone/components and @plone/theming: clean.
  • In the built CMS stylesheet: no cmsui layer, with preflight in base. /layers.css serves the new order.
  • Rechecked after merging main with Fix the server not loading translations, which broke hydration #207, which makes React keep the server-rendered page: /layers.css is the first stylesheet in the served HTML on every route (public, login, editor, contents), and the order after hydration is the same. Before Fix the server not loading translations, which broke hydration #207, browser checks saw the order of the client re-render only.

Part of #199.

Step A1 of #199. The CMS UI loads Tailwind with a plain import, so its
theme variables, preflight and utilities land in the declared theme,
base and utilities layers instead of a top-level cmsui layer. The reset
now sits below every other layer. Removes the cmsui layer and adds the
plone-content layer for block content CSS.

The quanta table row drag handle no longer relies on the global reset
to drop the basic button styles.
* origin/main:
  Fix the server not loading translations, which broke hydration (#207)
* origin/main:
  Releasing @plone/aurora 1.0.0-alpha.16
  Release @plone/contents 1.0.0-alpha.3
  Release @plone/publicui 1.0.0-alpha.8
  Release @plone/cmsui 1.0.0-alpha.11
  Release @plone/agave 1.0.0-alpha.8
  Release @plone/theming 1.0.0-alpha.8
  Release @plone/layout 1.0.0-alpha.13
  Release @plone/blocks 1.0.0-alpha.17
  Release @plone/plate 1.0.0-alpha.22
  Release @plone/react-router 2.0.0-alpha.7
  Release @plone/helpers 2.0.0-alpha.9
  Release @plone/registry 4.0.0-alpha.4
  Release @plone/quanta 1.0.0-alpha.1
  Release @plone/components 5.0.0-alpha.5
  Release @plone/client 2.0.0-alpha.8
  Release @plone/icons 1.0.0-alpha.1
  Release @plone/types 3.0.0-alpha.7
  Split Quanta and icons out of @plone/components into @plone/quanta and @plone/icons (#212)

# Conflicts:
#	packages/cmsui/styles/cmsui.css
The quanta Table moved from @plone/components to @plone/quanta in #212.
@sneridagh

Copy link
Copy Markdown
Member Author

Synced with main after #212: where @plone/icons/icons.css goes

#212 split @plone/quanta and @plone/icons out of @plone/components. It added @import '@plone/icons/icons.css' to cmsui.css, inside the old @layer cmsui { … } wrapper that this PR removes. That conflict is resolved like this:

@import 'tailwindcss';
@import '@plone/components/src/styles/basic/theme.css' layer(theme);
/* Its own `plone-icons` layer nests in `components`, below the utilities. */
@import '@plone/icons/icons.css' layer(components);

icons.css declares its own @layer plone-icons.

Why components:

  • Imported without a layer, plone-icons would become a new top-level layer that isn't in config.settings.cssLayers. Undeclared layers come after the declared ones, so the icon styles would sit above utilities and custom, and Tailwind classes on icons would stop winning.
  • In components, it becomes components.plone-icons. That's below utilities, as on main, where it was a sub-layer of cmsui under Tailwind's utilities.
  • One difference from main: the icon styles now sit above the reset in base, the same as every other component style in this PR. On main, preflight's svg { display: block } overrode .q.icon { display: inline-block }; here the icon's own display wins. That's the intended direction of this PR, since component styles shouldn't lose to the reset.

Checked:

  • This branch against current main: all 9 CMS chrome, contents and site frame screenshots (the A0 set) are pixel-identical. I took local references on main and compared this branch's build.
  • The whole stack at Content CSS Phase 11: theming guide for blocks and cleanup #219: 26/26 screenshots identical to the references taken before the sync. 182 acceptance tests pass.

The merge carries two other #212 follow-ups:

  • The Quanta Table moved to packages/quanta/src/components/Table/Table.tsx, and git carried the drag handle fix over.
  • This PR's news fragment for that fix moved from packages/components/news/ to packages/quanta/news/199.bugfix.

@sneridagh

Copy link
Copy Markdown
Member Author

LGTM!

This branch has not been deployed

No deployments
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