Contents

Class Definitions

Name a CSS class once, paste the declaration block that makes it look like your host Tailwind pane, and let composer, Preview, and published widgets apply those rules — or leave the definitions to your site.

Class names already travel. This catalog says what they mean

Widgets can already carry CSS class names on columns, rows, and the widget itself. Those names are a contract with the host stylesheet: rounded-xl, px-4, ring-parity-accent/30. RuleCMS does not invent those utilities. Until now it also did not define them.

Class definitions are the missing catalog: a project-wide map of class name → CSS declaration block. Fill it once and the composer, Preview, and — by default — published widgets apply those rules, even when the host never compiled that Tailwind pane.

This is the sibling of CSS Variables. Tokens are --name: value. Class definitions are .name { declaration-list }. They are independent toggles: a host that already ships Tailwind can turn class inclusion off and still include CSS variables, or the reverse.

Where this is really useful

You wantClass names onlyClass names plus this catalog
A widget that looks like a host Tailwind gallery even on a page that did not compile those utilitiesClasses are present. Nothing paints unless the host CSS already defines them.RuleCMS ships the declaration blocks with the widget. The embed matches Preview.
Multi-line Tailwind bodies — @supports, color-mix(), shadow/ring custom propertiesImpossible to reconstruct from the class name alone.Paste the declaration list. Nested at-rules and var() are allowed.
A host that already has the same utilitiesWorks today. Do not double-define.Turn published inclusion off. Composer and Preview still use the catalog.
The full project catalog is included — not “only classes this widget uses.” Same choice as CSS variables. Tree-shaking a utility catalog is easy to get wrong once values nest var() and @supports.

The project catalog

Open an environment, then Class Definitions. The page is project-scoped: Development, Staging, and Production share it.

  • Preview dumps the catalog as .name { … } blocks — the same shape as a Tailwind utilities pane, not :root.
  • Edit is a name plus a textarea for the declaration body. Invalid names and bodies are refused per row. Catalog Save is explicit.

Each entry is one class:

.rounded-xl {
  border-radius: var(--radius-xl);
}

.ring-parity-accent\/30 {
  --tw-ring-color: color-mix(in srgb, #6d28d9 30%, transparent);
  @supports (color: color-mix(in lab, red, red)) {
    --tw-ring-color: color-mix(in oklab, var(--color-parity-accent) 30%, transparent);
  }
}

Names are stored without a leading .. Paste from DevTools with a dot and RuleCMS strips one. Tailwind extras are allowed: /, :, [, ], %, ., _, -. On emit,/ is CSS-escaped so the selector is .ring-parity-accent\/30.

Values are a CSS declaration list, not a single token value. Semicolons, braces, @supports, calc(), var(), and color-mix() are allowed. A value must stay brace-balanced so it cannot close the wrapping rule and inject a new selector. @import, <script, and similar breakouts are rejected. At most 500 classes; 4000 characters per body.

What the renderer does with the catalog

SurfaceWhat happens
Composer canvas and PreviewAlways injects a stylesheet of .rulecms-render-surface .className { … }. The published-inclusion flag is ignored here so authors still see the utilities while they work.
Published widget (React SDK and HTML custom element)The widget fetch includes the catalog when inclusion is on. The renderer emits one scoped <style> of descendant class rules under that widget's published-key span. Nested collections inherit. You do not get a copy per collection.

You do not republish a widget to restyle a class. The catalog is joined when the host fetches the widget. The next uncached fetch picks up the current bodies. (Published traffic may sit in widget-cache for a short TTL — the same delay itemList already has.)

Turn off inclusion on published widgets

On the project's Class Definitions page, the Published widgets accordion holds two radios. Changing a radio saves immediately. Catalog Save is separate.

  • Include these class definitions when published widgets are rendered. A non-empty catalog is sent with the widget and the renderer defines the classes inside the widget. This is the default.
  • My apps already have these CSS classes. Do not include them again when the widget is being rendered. Published widgets still carry the class names on elements, but RuleCMS does not ship the declaration blocks. Your host stylesheet must define them.
Composer and Preview still use the catalog when inclusion is off. Only the published (and Development-draft) embed on your site stops carrying the extra rules. CSS variables have their own, independent toggle.
If you turn inclusion off, the host must define every class the widgets use. A missing utility on the live page paints as nothing. Check the published widget on a real route after you flip the setting.

How a published widget receives the catalog

Hosts already fetch the widget once. RuleCMS hangs the catalog on that same response as a sibling of the widget, its collections, and CSS variables — not folded into itemList.

{
  "success": true,
  "data": {
    "widget": { "publishedKey": "…", "itemList": "…", "…": "…" },
    "childCollections": { },
    "cssVariables": { "--radius-xl": "0.75rem" },
    "classDefinitions": {
      "rounded-xl": "border-radius: var(--radius-xl);"
    }
  }
}

classDefinitions is omitted when the catalog is empty, when inclusion is off, or if the catalog cannot be read. When inclusion is off, the same response also sends includeClassDefinitions: false so renderers that still receive a map must not emit it. Missing on the payload means include (legacy clients). The widget still loads.

The React renderer (@rulecms/widget-react) and the HTML custom element turn a non-empty catalog into one <style> scoped to that widget's published key, for example:

[data-rulecms-published-key="env---widget-abc"] .rounded-xl {
  border-radius: var(--radius-xl);
}

Good to know

  • This is not “compile Tailwind inside RuleCMS.” You paste declaration blocks you already have. RuleCMS stores and emits them.
  • Attaching a class name is still a different control. See CSS Classes. This catalog is what those names mean.
  • One catalog per project. Not per environment, not per widget.
  • Leave the catalog empty if the host owns every class. Names on elements still work. Nothing extra is sent to the published page.

Related docs