Copied utilities fight the host Tailwind pane
Tailwind is layers — base, components, utilities. RuleCMS Class Definitions emit as unlayered [data-rulecms-published-key] .name rules. The same utility can steamroll the host or lose to it depending on which stylesheet loads last. A class body cannot contain a top-level @layer.
Cascade layers is a setting for how those class definitions are emitted. It is not a second stylesheet and it does not compile Tailwind. You pick utilities or components. RuleCMS wraps the existing class sheet.
When to use it / when not to
| You want | Leave unlayered | Wrap in a layer |
|---|---|---|
| Copied utilities to compete with host Tailwind the same way Tailwind utilities do | Unlayered rules win or lose by stylesheet order. A later host sheet can override them — or they can override the host. | Pick utilities. Class rules sit in @layer utilities and compete with the host pane. |
| Component-style classes that should sit under host utilities | They fight utilities as unlayered CSS. | Pick components. Host utilities still win the cascade the way Tailwind intends. |
| A host that already puts these class names in a layer | Works today. Do not wrap them again. | Turn published inclusion off. Composer and Preview still wrap when the setting is defined. |
utilities vs components. Use utilities for copied Tailwind utilities. Use components when the classes should lose to host utilities. There is no free-text layer name and no @layer reset, theme, utilities list.The project catalog
Open an environment, then Cascade layers. The page is project-scoped: Development, Staging, and Production share it.
- Preview shows a short example using
.rounded-xl— wrapped or unlayered — not a pasted stylesheet editor. - Edit is one select: Do not wrap (default),
utilities, orcomponents. Saving “do not wrap” deletes the setting. Catalog Save is explicit.
A typical wrapped emit looks like this:
@layer utilities {
[data-rulecms-published-key="env---w"] .rounded-xl {
border-radius: var(--radius-xl);
}
}Empty or omitted is today's unlayered class emit. This setting never styles :root, html, or body.
What the renderer does with the catalog
| Surface | What happens |
|---|---|
| Composer canvas and Preview | Always wraps the surface class stylesheet when a layer is set. The published-inclusion flag is ignored here so authors still see cascade while they work. |
| Published widget (React SDK and HTML custom element) | When inclusion is on and a layer is set, the class stylesheet is wrapped. When inclusion is off, classes still emit — unlayered — even if a layer is saved. If there are no class definitions, nothing is emitted. |
You do not republish a widget to change the wrap. The setting is joined when the host fetches the widget. The next uncached fetch picks up the current choice.
Published widgets
On the project's Cascade layers page, the Published widgets accordion holds two radios. Changing a radio saves immediately. Catalog Save is separate.
- Include this cascade layer wrapper when published widgets are rendered. A saved layer wraps the class stylesheet. This is the default.
- My apps already put these utilities in a layer. Do not wrap them again when the widget is being rendered. Published widgets still carry class definitions, but RuleCMS does not wrap them. Your host stylesheet already owns cascade.
How a published widget receives the setting
Hosts already fetch the widget once. RuleCMS hangs the setting on that same response as a sibling of the widget and its class definitions — not folded into itemList. The fields are classLayer and, when wrapping is off, includeClassLayer: false.
{
"success": true,
"data": {
"widget": { "publishedKey": "…", "itemList": "…", "…": "…" },
"childCollections": { },
"classDefinitions": {
"rounded-xl": "border-radius: var(--radius-xl);"
},
"classLayer": "utilities"
}
}classLayer is omitted when the setting is empty, when inclusion is off, or if the catalog cannot be read. When inclusion is off, the same response also sends includeClassLayer: false so renderers that still receive a layer name must not wrap. Missing on the payload means include (legacy clients). The widget still loads.
The React renderer (@rulecms/widget-react) and the HTML custom element wrap the existing class stylesheet, for example:
@layer utilities {
[data-rulecms-published-key="env---w"] .rounded-xl {
border-radius: var(--radius-xl);
}
}Good to know
- One setting per project. Not per environment, not per widget. At most one layer entry.
- This is not generic
@layerauthoring. You cannot name a layerresetor write a layer-order list. - React and the HTML embed this pass. Other framework SDKs do not wrap class emit yet.
- Leave the setting empty if unlayered emit is what you want. Class names still work. Nothing extra is sent.
Related docs
- Class Definitions — the utility catalog this setting wraps
- CSS Variables — tokens those classes can point at
- Fonts — the typeface catalog
- Keyframes — named
@keyframes - Position try — named
@position-tryfallbacks - Themes — host-dark token overrides
- CSS Properties — typed
@property - Widget chrome — color-scheme and selection on the widget root
- HTML Custom Element Embed
- Development Integration
- API Reference — the public widget GET, including
classLayer - Projects, Environments & Tokens
- The Composer