Skip to content

Configuring the CMS Tailwind JIT Module

The CMS Tailwind JIT module supports a custom CSS file and a custom JavaScript configuration file for in-browser compilation. Both are optional. If neither is present, the module uses Tailwind's default configuration.

Custom CSS for CMS Content

The CMS Tailwind JIT module ignores the standard tailwind-source.css file used for theme compilation. To add custom CSS that applies to CMS content, create a web/tailwind/tailwind.browser-jit.css file in your theme. The contents are passed to the in-browser Tailwind JIT compiler and included in the compiled styles for CMS content.

Overriding the CSS File Path

By default the module looks for web/tailwind/tailwind.browser-jit.css in your theme directory. You can point this to any CSS file in your theme - which is useful for sharing CSS with the CMS JIT compiler rather than maintaining a separate file.

To set the path, create a etc/cms-tailwind-jit-theme-config.json file in your theme:

app/design/frontend/My/Theme/etc/cms-tailwind-jit-theme-config.json
{
  "tailwindBrowserJitCssPath": "../../../../../app/design/frontend/My/Theme/web/tailwind/tailwind.browser-jit.css"
}

Path resolution rules:

  • Paths starting with / are treated as absolute filesystem paths
  • All other paths are relative to the theme directory
  • If the file does not exist or is unreadable, the module silently continues without custom CSS

Tailwind v4: CSS Custom Properties for CMS Styles

Since Hyvä 1.4, Tailwind v4 is the default and uses a CSS-native configuration approach - there is no tailwind.config.js to merge into, and the browser JIT config cannot be extended with imports. This means there is no direct equivalent to the Tailwind v3 config merge technique.

In Tailwind v4, custom values like colors, spacing, and typography scales are defined as CSS custom properties using the @theme directive in your theme's CSS. The CMS Tailwind JIT compiler runs in the browser against the live page, so those variables are already in scope - you can reference them directly in CMS content without any additional configuration.

For any CMS-specific styles, use the tailwind.browser-jit.css file and write against the same CSS custom properties your theme defines:

web/tailwind/tailwind.browser-jit.css
/* Reference theme CSS custom properties defined via @theme in your theme */
.cms-callout {
    border-left: 4px solid var(--color-primary);
    padding: var(--spacing-4);
    background: var(--color-primary-lighter);
}

For a full reference on CSS custom properties and how they work with Tailwind v4, see CSS Variables and Tailwind CSS.

JavaScript Configuration for CMS Content

By default, the CMS Tailwind JIT module looks for a JavaScript configuration file at web/tailwind/tailwind.browser-jit-config.js within your theme directory. This file follows the same structure as tailwind.config.js but with significant restrictions due to the browser environment.

Overriding the JavaScript Configuration File Path

To use a different location, create a etc/cms-tailwind-jit-theme-config.json file in your theme:

app/design/frontend/My/Theme/etc/cms-tailwind-jit-theme-config.json
{
  "tailwindBrowserJitConfigPath": "../../../../../app/design/frontend/My/Theme/web/tailwind/tailwind.browser-jit-config.js"
}

This is uncommon. Omitting the file and relying on the default config path is sufficient for most projects.

Path resolution rules:

  • Paths starting with / are treated as absolute filesystem paths
  • All other paths are relative to the theme directory
  • If the file does not exist or is unreadable, the module silently falls back to the default Tailwind configuration

Browser Context Limitations

The browser JIT config is evaluated in the browser, not in Node.js. This limits what can be included.

Allowed in browser JIT config:

  • module.exports.theme configuration object
  • Two specific imports:
    const { spacing } = require('tailwindcss/defaultTheme');
    const colors = require('tailwindcss/colors');
    

Not allowed in browser JIT config:

  • require() calls for custom plugins or external files
  • resolveConfig() function calls
  • Node.js filesystem operations
  • Any code outside the module.exports object
  • @import directives in the browser JIT CSS file (no filesystem access in the browser)

Example tailwind.browser-jit-config.js

A valid browser JIT configuration file that customizes the container and extends the color palette:

web/tailwind/tailwind.browser-jit-config.js
// Only these two imports are supported in the browser-based compiler
const { spacing } = require('tailwindcss/defaultTheme');
const colors = require('tailwindcss/colors');

module.exports = {
  theme: {
    // Override default container behavior for CMS content
    container: {
      center: true,
      padding: spacing["6"]
    },
    extend: {
      colors: {
        // Custom color definitions - these must match your theme's color palette
        'my-gray': '#888877',
        primary: {
          lighter: colors.purple['300'],
          DEFAULT: colors.purple['800'],
          darker: colors.purple['900'],
        },
      }
    },
  }
}

Merging the JavaScript Config with the Standard Tailwind Config

Tailwind v3 only (Hyvä 1.3.x and earlier)

This approach requires Tailwind v3. In Tailwind v4 projects (Hyvä 1.4+), the JavaScript config merge does not apply. See Tailwind v4: CSS Custom Properties for CMS Styles above.

To avoid duplicating theme extensions in both tailwind.config.js and tailwind.browser-jit-config.js, append this deep-merge snippet to the end of your tailwind.config.js:

web/tailwind/tailwind.config.js
// Deep merge the browser JIT config into the standard config
// This keeps both configs in sync automatically
if (require('fs').existsSync('./tailwind.browser-jit-config.js')) {

    // Helper function to check if a value is a plain object
    function isObject(item) {
        return (item && typeof item === 'object' && !Array.isArray(item));
    }

    // Recursively merge source objects into target object
    // Arrays are replaced entirely, objects are merged recursively
    function mergeDeep(target, ...sources) {
        if (!sources.length) return target;
        const source = sources.shift();

        if (isObject(target) && isObject(source)) {
            for (const key in source) {
                if (isObject(source[key])) {
                    if (!target[key]) Object.assign(target, { [key]: {} });
                    mergeDeep(target[key], source[key]);
                } else {
                    Object.assign(target, { [key]: source[key] });
                }
            }
        }

        return mergeDeep(target, ...sources);
    }

    // Merge browser-jit-config into this config
    mergeDeep(module.exports, require('./tailwind.browser-jit-config.js'));
}

This keeps CMS content styles and template styles in sync automatically, without duplicating theme customizations across both config files.