Skip to content

Canvas Builder — Tailwind CSS Setup

Canvas Builder's shipped Tailwind profile uses Tailwind's native responsive prefix convention (md:, lg:, xl:), not Bootstrap's infix style. Apply the Tailwind profile first (General → Framework → select TailwindUse this framework as my base), then follow the steps below.


1. Build setup (Tailwind v4)

Tailwind v4 is configured in CSS — no tailwind.config.js. In your theme's entry stylesheet, import Tailwind and point @source at (a) a file holding Canvas Builder's runtime classes and (b) the module's component templates:

/* src/input.css */
@import "tailwindcss";

/* Classes Canvas Builder applies from config at RUNTIME — Tailwind can't see
   these by scanning source, so export them to a file (see step 2). */
@source "./canvas-builder-safelist.txt";

/* Static classes in Canvas Builder's own component templates. */
@source "../../../../modules/custom/canvas_builder/components";

Build:

npm install -D tailwindcss @tailwindcss/cli
npx @tailwindcss/cli -i src/input.css -o dist/main.css --minify

Then load dist/main.css from your theme's *.libraries.yml.

Tailwind v3? Use a tailwind.config.js with content (your templates + ../../modules/custom/canvas_builder/components/**/*.twig) and a safelist array holding the same exported list. v3 calls it content; v4 calls it @source. Everything else is identical.

Verified: every class in the shipped Tailwind profile — colors, text-align, p-*/m-* and their per-side forms (pt-*, px-*, …), gap-*, grid-cols-1..12, items-*/justify-*, flex-row-reverse, min-h-screen/h-fit and the container widths, each with its md:/lg:/xl: variant — compiles under Tailwind v4 from the exported safelist.

The per-side spacing classes are the reason you must export the safelist rather than hand-write one: the box-model editor derives pt-6 from p-6 at runtime, so those names appear in no source file and Tailwind purges them unless the export lists them.

npm workspaces gotcha: if your project root declares npm workspaces, npm run/npm install inside the theme may resolve to the workspace root instead of the theme. Run the Tailwind CLI directly (as above) or build the theme outside the workspace.

2. Export the safelist

Canvas Builder applies its utility classes from config at runtime, so Tailwind can't discover them by scanning templates — you must hand it the list:

  • From the editor: Administration → Canvas Builder → General → Framework → Tailwind Safelist lists every class currently mapped in your style tables and layout maps. Click the textarea to select all, and save it as the @source file (canvas-builder-safelist.txt). It updates automatically whenever you change style tables — re-export after any change.
  • Scripted (CI): generate the identical list with Drush so the build never drifts (run with the Tailwind profile active):
drush eval 'echo implode(PHP_EOL, \Drupal::service("canvas_builder.framework_profiles")->getSafelistClasses());' \
  > themes/custom/<theme>/src/canvas-builder-safelist.txt

See FRAMEWORKS.md → Exporting & importing classes for moving the whole class config between sites.


Layout maps

The Tailwind profile pre-fills the layout matrices (General → Columns / Section) with Tailwind-native classes:

Viewport Prefix Example
Mobile (none) gap-4 / justify-start
Tablet md: md:gap-4 / md:justify-start
Desktop lg: lg:gap-4 / lg:justify-start
Large Desktop xl: xl:gap-4 / xl:justify-start

columns.count is stored but not emitted. The column count resolves per viewport via --cb-columns-count-{breakpoint}, which one class per enum value cannot express. The grid-cols-* rows stay in config (so customisations survive) and still reach the safelist, but the renderer no longer applies them.

section.container_type is base-only by design (mx-auto max-w-screen-lg is already a responsive container — no infix needed).

Alignment families are emitted as real, per-viewport classes. columns.valign/columns.halign (items-*/justify-*) and grid.grid_valign/grid.grid_halign (items-*/justify-items-*) all reach .cb-columns — Canvas Builder resolves which layout mode (columns vs. grid) is active at each viewport and only stamps the matching family's classes there, so both can be configured together without conflict. Tailwind ships justify-items-*, so grid_halign gets full coverage here (unlike Bootstrap, which has no such utility and stays CSS-var-only for that family).


Custom colors

Add your palette in CSS with @theme (v4), then update Administration → Canvas Builder → Styles with matching option rows using the generated class names:

/* src/input.css */
@import "tailwindcss";

@theme {
  --color-primary:   #1a56db;
  --color-secondary: #6c757d;
}

(Tailwind v3: use theme.extend.colors in tailwind.config.js instead.)

Matching options in settings:

bg_color_classes:
  - label: Primary
    classes:
      mobile: bg-primary
      tablet: md:bg-primary
      desktop: lg:bg-primary
      large_desktop: xl:bg-primary


Notes

  • The color swatch in the editor reads colors from the preview iframe at runtime — ensure your compiled CSS is loaded in the preview so swatches reflect the real theme palette.
  • Re-export the safelist (step 2) and rebuild after every change to your style tables or layout maps, or new class options won't have any CSS.