Download the PHP package craftpulse/craft-tailwind without Composer
On this page you can find all versions of the php package craftpulse/craft-tailwind. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download craftpulse/craft-tailwind
More information about craftpulse/craft-tailwind
Files in craftpulse/craft-tailwind
Package craft-tailwind
Short Description Tailwind CSS class merging and named-slot class builder for Craft CMS 5
License proprietary
Informations about the package craft-tailwind
Tailwind for Craft CMS
Server-side Tailwind CSS class merging for Craft CMS 5 templates. Resolves conflicting utility classes, organizes styles into named slots, and injects CSS custom properties -- all without client-side JavaScript.
What it solves
Component overrides without conflicts
A button component defines default colors. A page template wants to override just the color, but concatenating classes produces bg-brand-accent bg-red-500 -- both classes render, the cascade picks a winner unpredictably, and the source is impossible to reason about.
With craft-tailwind, the merge engine understands which utilities conflict and keeps only the last one per CSS property:
Dynamic colors without safelisting
A CMS field lets editors pick a brand color. Tailwind tree-shakes unused classes at build time, so writing bg-{{ color }} produces nothing -- the class never made it into the build.
CSS custom properties sidestep this entirely. Define your palette once in plugin settings, reference the variables in your templates with arbitrary value syntax, and swap values at runtime:
Form field modifiers
A form input has default styling. Error state needs a red border. Disabled state needs muted colors. Without merge, layering modifier classes means manually tracking which base classes to remove:
Installation
You can install Tailwind via the Plugin Store in the Craft control panel, or from the command line.
With DDEV:
Without DDEV:
Tailwind works on Craft 5.x and requires PHP 8.2 or later.
Configuration
Settings can be managed through the control panel (Settings > Plugins > Tailwind) or via a config file. File-based configuration takes precedence over CP settings.
Config file
Create config/tailwind.php:
When a setting is defined in both the config file and the CP, the config file value wins. The CP settings page shows a warning on each overridden field.
About the cacheSize setting
The merge engine is called every time you use craft.tailwind.merge() or build a ClassList. To avoid re-parsing the same class strings over and over within a single request, results are kept in an in-memory LRU cache (Least Recently Used). When the cache fills up, the entry that hasn't been used for the longest gets evicted to make room — so "hot" class strings (e.g. your main button's classes) stay resident.
The cache is per-request: it lives only for the duration of one PHP process. You don't need to think about invalidation. Set cacheSize to 0 to disable caching entirely (useful when debugging a merge).
Tip — HMR and the LRU don't interact. Because the cache is per-request, it starts empty on every page load. Editing
tailwind.config.js, your CSS entry, the plugin settings, or anything Vite picks up will be reflected on the very next request — there's no stale cache to clear during development. The one place merges can survive across requests is inside Craft's{% cache %}blocks; that's normal template caching, not the plugin's LRU, and the usual{% cache %}invalidation rules apply.
Multi-environment configuration
The config file supports Craft's standard multi-environment pattern:
Usage
Class merging
craft.tailwind.merge() resolves conflicting Tailwind utilities. The last class per CSS property group wins:
Accepts any number of arguments. Each argument is a space-separated class string.
Named-slot ClassList
When a component has many style concerns, a flat class string becomes hard to override selectively. The ClassList object splits classes into named slots, each representing a single responsibility:
The ClassList object is immutable. Every mutation returns a new instance:
Works naturally with Craft's {% tag %} helper:
CSS variables
Define CSS custom properties in plugin settings (or config/tailwind.php), then render them as a <style> tag in your layout. The include() method returns a Twig\Markup object, so you don't need the |raw filter:
CSP and subresource integrity
Pass attributes to the <style> tag — useful for Content Security Policy nonces or other custom attributes:
The plugin doesn't assume a nonce source — wire it up to your CSP module's per-request nonce however you expose it (a variable, a service, a Twig global).
Auto-inject
If you don't want to think about where the tag goes, enable the Auto-Inject setting (CP or config/tailwind.php). The plugin will register the style block via Craft's View::registerCss() on every site request automatically:
Auto-inject is skipped on console requests and CP requests. If you use a dynamic per-request CSP nonce, keep auto-inject disabled and call {{ craft.tailwind.include({ nonce: cspNonce }) }} in your layout so the nonce can be resolved at render time.
Inspecting variables
Use craft.tailwind.cssVariables when you need to look up or iterate variables instead of rendering them:
Sanitization and naming
The CssVariables object sanitizes values to prevent CSS injection. Values containing characters outside the safe set (letters, digits, hyphens, underscores, dots, hashes, commas, parentheses, percent signs, slashes, spaces, and quotes) are silently dropped. In devMode, dropped values are logged as warnings.
Variable names are auto-prefixed with -- if missing, so both color-brand and --color-brand resolve to the same property.
Version detection
The plugin auto-detects whether your project uses Tailwind v3 or v4 and selects the correct merge engine. Detection follows this priority:
- CSS signals -- scans the CSS path for
@import "tailwindcss"or@themedirectives (definitive v4 indicators) - Config files -- looks for
tailwind.config.{js,ts,cjs,mjs}in the buildchain path (v3 indicator) - Fallback -- defaults to v4 with a devMode warning
Set buildchainPath and cssPath in settings to point detection at the right directories. When unset, both default to the project root.
To skip detection entirely, set tailwindVersion to '3' or '4' explicitly.
Debug toolbar panel
When Craft's debug toolbar is enabled (devMode + a user with debug access), a Tailwind panel appears alongside the others. It records every merge operation during the current request and shows:
- Total calls / unique inputs — how many times
merge()ran, and how many distinct input strings were seen - Cache stats — hit count, hit rate, and current LRU entry count
- Per-merge detail — the input, the resolved output, whether a conflict was actually resolved (vs passthrough), the call count, and the template that ran the merge
Use it to answer questions like "why is bg-red-500 not appearing on the page?" (find the merge input where it was overridden) or "is my cache actually helping?" (check the hit rate).
The panel has no overhead outside of debug-enabled requests — data collection only runs when the debug module is loaded.
Typography plugin support
The @tailwindcss/typography plugin registers prose-{size} and prose-{theme} classes that neither underlying merge engine knows about by default — so out of the box prose prose-sm prose-lg passes through unchanged. The plugin's typography setting opts you into a curated conflict-group config that covers the suffixes shipped by @tailwindcss/typography 0.5.x:
- Sizes:
sm,base,lg,xl,2xl - Colors / themes:
gray,slate,zinc,neutral,stone,invert
Enable it in plugin settings or in config/tailwind.php:
Now size and theme conflicts resolve last-wins, while size and color stay orthogonal:
A typical rich-text area with editor-controlled size:
Custom typography themes
If you've registered your own prose-* themes — for example a brand variant via an @utility prose-mybrand { ... } block on v4, or a theme.extend.typography.mybrand entry on v3 — add the suffixes to the extras lists so the merger treats them as conflict-group members:
With the extras above, merge('prose prose-slate', 'prose-mybrand') resolves to prose prose-mybrand. Suffixes are stored without the prose- prefix.
You can also manage the toggle and extras through the CP settings page (under Typography). Defaults are always included — extras only need entries for suffixes you've registered yourself.
Why opt-in?
Resolving prose-* conflicts by default would surprise users who use the typography plugin alongside their own prose-* naming conventions, or who don't use the typography plugin at all and would rather see their prose-* classes pass through unchanged. The toggle keeps the default behavior predictable and lets typography users enable resolution explicitly.
API reference
Template variables (craft.tailwind)
| Property / Method | Returns | Description |
|---|---|---|
.merge('a', 'b', ...) |
string |
Merge multiple class strings |
.classes({ slot: 'classes' }) |
ClassList |
Named-slot class builder |
.version |
string |
Detected Tailwind version ('3' or '4') |
.cssVariables |
CssVariables |
CSS custom properties container |
.include(attributes = {}) |
Twig\Markup |
Ready-to-render <style> tag — no \|raw required |
ClassList methods
| Method | Returns | Description |
|---|---|---|
__toString() |
string |
All slots merged into a single class string |
.get(slot) |
?string |
Value of a single slot |
.override({ slot: '...' }) |
ClassList |
New instance with replaced slots |
.extend({ slot: '...' }) |
ClassList |
New instance with appended slot values |
.without('slot', ...) |
ClassList |
New instance without named slots |
.merge('additional') |
string |
All slots + additional merged to a string |
.toArray() |
array |
Named slots as an associative array |
CssVariables methods
Use these when you need introspection; for rendering prefer craft.tailwind.include() on the variable.
| Method | Returns | Description |
|---|---|---|
__toString() |
string |
:root { ... } CSS block |
.asCss() |
string |
:root { ... } CSS block (no <style> wrapper) |
.get(name) |
?string |
Value of a single variable |
.has(name) |
bool |
Whether a variable exists |
.all() |
array |
All variables as key-value pairs |
.isEmpty() |
bool |
Whether the collection is empty |
Credits
This plugin wraps two PHP merge libraries:
- gehrisandro/tailwind-merge-php (Tailwind v3)
- tales-from-a-dev/tailwind-merge-php (Tailwind v4)
Brought to you by CraftPulse.
All versions of craft-tailwind with dependencies
craftcms/cms Version ^5.0.0
michtio/tailwind-merge-v3 Version ^1.2
michtio/tailwind-merge-v4 Version ^0.3