Contents

Generate Tailwind CSS

Turn the Tailwind class names on this widget into CSS this widget owns. Paste your theme so design-system classes compile the same way they did in your project.

Why your widget looks unstyled

When you paste a component from your Tailwind project into RuleCMS, the markup still carries the class names — rounded-xl, px-4, bg-brand-500. The CSS behind those names does not come with them. In your project, Tailwind scanned your source at build time and wrote that CSS. RuleCMS does not run that build over widget content, so a class sitting on a column has nothing that turns it into a declaration.

Generate Tailwind CSS on this widget's CSS Settings page closes that gap. It reads the class names the widget and its child collections already use, optionally takes your design tokens, compiles the pair with Tailwind itself, and writes the result into this widget's CSS catalog.

This is a one-shot conversion, not a live link. After it runs, the widget owns the CSS. Changing the component later in your own project does not update RuleCMS. Generate again when the class names or the theme change.

What this feature does

Generation walks the widget tree, compiles each class name it finds, and merges the CSS into four catalog slices this widget already has:

  • Class definitions — the declaration block for each utility, including variants such as hover: and md:.
  • CSS variables — only the theme tokens those classes actually reference, such as --spacing or --color-brand.
  • Keyframes — named frames for stock animate-* utilities.
  • CSS properties — the @property registrations shadows, rings, transforms, and filters need so they compose.

Classes you already wrote by hand are kept. Generated utilities are appended after them. Publish flags are not rewritten — generation decides what CSS exists, not whether the embed includes it.

Why some things cannot work

The limits below are architectural, not missing polish. They exist because a widget is a guest on someone else's page, and because RuleCMS cannot run code you paste.

ConstraintWhat that means for you
A widget cannot reset the host pageTailwind Preflight — the base layer that zeros margins and sets box-sizing — is never applied. If your component depended on those resets, add them yourself under Widget chrome.
We never run your JavaScriptA pasted tailwind.config.js is read as text, not executed. Plugins, require(), spreads, and function calls cannot run. That is why plugin classes such as prose never generate.
Class names have a character allowlistNames cannot contain !, #, =, @, *, &, >, or parentheses. Square brackets are allowed, so w-[42px] works and bg-[#1a4f8a] does not.
Only class names written in the tree are seenA class computed at runtime — bg-${color}-500 — is invisible, the same way Tailwind's own scanner would miss it. The name has to appear literally on the widget or a child collection.
This is a snapshotGeneration writes CSS this widget owns. It is not connected to your repository. Re-run it when you add classes or change the theme.

How to use it

  1. Open the widget's CSS Settings page.
  2. If you have unsaved edits on a catalog form, save or discard them first. The button is disabled while a form is dirty so generation cannot overwrite work you have not stored.
  3. Click Generate Tailwind CSS. A dialog opens and starts analysing the widget. Nothing is written until you click Generate.
  4. Read the preview counts — classes found, and how many class definitions, CSS variables, and CSS properties would be added. The skipped list is the only place a class that produced nothing is reported.
  5. Optionally paste your theme into Paste your Tailwind theme or config. If the component uses your own colour or spacing names, this step is what makes those classes generate. Leaving it blank is valid — generation then uses Tailwind's defaults plus any variables already on this widget. After you paste, click Analyze with this theme so the preview includes those tokens.
  6. Click Generate. The button stays disabled while analysis is running, and if the preview would write nothing. The dialog locks while it writes, then shows whether generation succeeded. Click OK on success, then publish the widget. Live embeds do not change until you publish.

The information icon next to the button and the dialog title opens this page in a new tab, so you can keep the dialog open while you read.

What to paste

You do not have to tell us whether the project is Tailwind v3 or v4. Paste either of the following and we detect the format. Leave the box blank if you have no custom theme or config.

Tailwind v4 — the @theme block in your CSS file

Usually app/globals.css or src/index.css, next to @import "tailwindcss". You can paste the whole stylesheet; only @theme declarations are read. A bare list of --token: value lines also works.

@theme {
  --color-brand: #6d28d9;
  --radius-card: 12px;
}

Tailwind v3 — your tailwind.config.js

In your project root. Paste the whole file, or just the theme object. Nested keys flatten: colors.brand becomes --color-brand, which is what lets bg-brand compile.

module.exports = {
  theme: {
    extend: {
      colors: { brand: '#6d28d9' },
      borderRadius: { card: '12px' },
    },
  },
};
We read the config without running it. Values built from require(), a variable, a function call, or a spread cannot be resolved. Those tokens are listed after you generate under "Tokens we could not read." Paste the resolved values, or paste the v4 @theme block if you have one.

After the first successful generate, the tokens that were actually used are stored on this widget. A later run can reuse them without another paste. Only used tokens are stored — paste seven colours and use three, and three persist. Start using a fourth later and paste again, or put the full set on CSS Variables yourself so they all stay.

What we support

These compile when the class name is stored on the widget and, for design-system names, when the matching token is available.

CategoryExamples
Plain utilitiesflex z-50 w-full truncate sr-only
Theme-backed spacing, type, radiusp-4 rounded-xl text-base font-sans
Fractions, negatives, pxw-1/2 -mt-4 mt-px
Alpha modifierstext-red-500/50 ring-brand/30
Breakpointssm: md: lg: xl: 2xl: max-md: min-[600px]:
Pseudo-classes and pseudo-elementshover: focus: focus-visible: before: after: placeholder:
Relational variantsgroup-hover: peer-checked: — the group / peer marker classes themselves generate nothing; leave them on the markup. See Silent surprises.
Media, direction, ARIAdark: motion-reduce: print: rtl: aria-expanded:
Stacked variantsdark:hover: sm:focus-visible:
Composable utilitiesshadow-sm ring-1 blur-sm scale-95 from-red-500
Arbitrary values with safe charactersw-[42px] has-[:checked]:flex supports-[display:grid]:flex

Design-system classes such as bg-brand-500 work only when the matching token is on this widget or in the paste. Without that token they look exactly like a typo.

What we do not support

This classWhy it is skippedWhat to do
bg-[#1a4f8a]# is not allowed in a class nameAdd --color-brand: #1a4f8a to the theme and use bg-brand
data-[state=open]:flex= is not allowedDefine the rule under Class Definitions
!flex! is not allowedWrite the declaration with !important by hand, or rely on catalog order — generated utilities already win over earlier hand-written classes
@md:flex, @container@ is not allowed; container queries drop outUse a breakpoint variant such as md:flex, or write the container query under Class Definitions
*:p-4, [&>*]:p-4*, &, and > are not allowedPut p-4 on the children, or write the child selector under Class Definitions
bg-(--my-color)Parentheses are not allowedRegister the colour as a theme token and use bg-my-color
prose, other plugin classesPlugins never runCopy the plugin CSS into Class Definitions
Your own btn from @utility or @applyOnly @theme tokens are read from a pasteDefine btn under Class Definitions
A class built in JavaScript at runtimeNothing in the tree to findPut the full class name on the component as a literal string

Silent surprises

Most failures appear in the skipped list. These three do not, or they appear in a way that is easy to misread.

Class-based dark mode follows the operating system

Generated dark: classes use @media (prefers-color-scheme: dark). If your project redefined the variant — Tailwind v4 @custom-variant dark (&:where(.dark, .dark *)), or v3 darkMode: 'class' — that redefinition is dropped. The class is generated, the CSS is valid, and nothing is reported as skipped. It just responds to the OS setting instead of a .dark ancestor.

If your site has a dark-mode toggle, check it by hand after you generate. To keep the class-based trigger, add a theme under Themes that sets the tokens under .dark, or rewrite the dark: rules under Class Definitions.

group and peer in the skipped list are expected

They are marker classes. They carry no CSS, so generation reports them as "Not a Tailwind utility." The variants that depend on them — group-hover:flex, peer-checked:hidden — do generate, and they match the literal class in the markup. Do not remove group or peer from the component because the report mentioned them.

A token that overrides a Tailwind default retunes every utility

If your paste (or this widget's variables) sets --spacing: 8px, then p-4 becomes 32px instead of 16px. That is what your project does, so it is correct — and it is listed in the preview under "Overrides a Tailwind default" so you can see the reach before you confirm.

Workarounds

What you wantedDo this instead
A hex colour in the class nameMove the colour into the theme as --color-* and use bg-* / text-*
Plugin output such as TypographyPaste the compiled plugin CSS into Class Definitions
A custom @utility or @apply classRecreate it under Class Definitions. Generation will not delete a hand-written class on the next run
Class-based dark modeUse Themes to override tokens under .dark, or rewrite the generated dark: bodies
Resets you used to get from PreflightAdd them on Widget chrome
A class only assembled in codeWrite the full name on the node so generation can see it
A computed value in a v3 configPaste the resolved literal, or paste the v4 @theme block

After you generate

  • Review the new entries on Class Definitions and CSS Variables. You can edit any of them; the next generate overwrites a generated name and leaves names that exist only on the widget.
  • Publish the widget. Composer and Preview already read the draft; the live embed does not change until you publish.
  • Generate again after you add class names or change the theme. The second run does not need a paste if the tokens are already on this widget.

Related guides

  • Class Definitions — hand-write anything generation cannot store
  • CSS Variables — keep the full token set on the widget so later generates do not need another paste
  • Themes — host dark-mode strategy when dark: should not follow the OS
  • Widget chrome — resets you no longer get from Preflight
  • Publishing — draft versus live
  • Widgets — CSS Settings and the rest of the widget