gehrisandro/tailwind-merge-laravel
Merge Tailwind CSS class strings in Laravel and auto-resolve conflicts so later utilities win. Ideal for overriding classes in Blade components. PHP/Laravel port of tailwind-merge. Supports Tailwind v3.0–v3.3 (Laravel 10).
Installation:
composer require gehrisandro/tailwind-merge-laravel
Publish config (optional):
php artisan vendor:publish --provider="TailwindMerge\Laravel\TailwindMergeServiceProvider"
First Use Case:
In a Blade component, replace $attributes->class with $attributes->twMerge():
<!-- components/button.blade.php -->
<button {{ $attributes->twMerge('px-4 py-2 bg-blue-500 text-white') }}>
Click Me
</button>
Override in parent view:
<x-button class="bg-red-500 hover:bg-red-600" />
Output: <button class="px-4 py-2 bg-red-500 text-white hover:bg-red-600">
<!-- components/card.blade.php -->
<div {{ $attributes->twMerge('p-6 rounded-lg shadow-md bg-white') }}>
{{ $slot }}
</div>
<x-card class="bg-gray-100 p-4 rounded-none">
Content
</x-card>
<!-- components/avatar.blade.php -->
<div {{ $attributes->withoutTwMergeClasses()->twMerge('flex items-center') }}>
<img {{ $attributes->twMergeFor('img', 'w-10 h-10 rounded-full') }} src="{{ $src }}" alt="{{ $alt }}">
<span {{ $attributes->twMergeFor('name', 'ml-3') }}>{{ $name }}</span>
</div>
Usage:
<x-avatar class="items-start" class:img="w-12" class:name="ml-4" />
Use @twMerge for inline class merging:
<div @twMerge('text-lg', 'text-red-500')>Text</div>
For non-Blade contexts (e.g., email templates, API responses):
use TailwindMerge\Laravel\Facades\TailwindMerge;
// In a service or controller
$mergedClasses = TailwindMerge::merge('bg-blue-500 hover:bg-blue-600', 'bg-red-500');
// Or via helper
$merged = twMerge('p-4', 'p-6');
Merge classes dynamically based on conditions:
<div {{ $attributes->twMerge(
'bg-' . ($isActive ? 'green' : 'gray') . '-500',
'hover:bg-' . ($isActive ? 'green' : 'gray') . '-600'
) }}>
Content
</div>
Non-Tailwind Classes:
custom-class) are preserved but may cause unexpected behavior if they conflict with Tailwind’s internal logic.config/tailwind-merge.php under classGroups:
'classGroups' => [
'custom' => [['custom-class']],
],
Arbitrary Values:
w-[200px]) always win. Later arbitrary values override earlier ones.!important equivalents (e.g., !w-[200px]) for explicit overrides.Dark Mode Conflicts:
dark:bg-gray-800) are merged like any other class, but ensure your custom dark variants are registered in classGroups.Cache Invalidation:
classGroups:
php artisan cache:clear
Inspect Merged Output: Use the facade to debug:
dd(TailwindMerge::merge('class1', 'class2')); // Inspect merged result
Validate Tailwind Config:
If merging fails, ensure your tailwind.config.js aligns with the package’s assumptions (e.g., no conflicting color names like bg-primary).
Check for Typos:
The package throws exceptions for invalid Tailwind classes. Use TailwindMerge::validate() to pre-check:
if (!TailwindMerge::validate('invalid-class')) {
// Handle error
}
Custom Class Groups:
Extend classGroups for custom utilities (e.g., bg-brand-*):
// config/tailwind-merge.php
'classGroups' => [
'brand' => [
['bg' => ['brand-50', 'brand-100', 'brand-500']],
],
],
Dynamic Prefixes:
Override the prefix globally via .env:
TAILWIND_MERGE_PREFIX=tw-
Performance:
For high-traffic apps, disable caching in config/tailwind-merge.php:
'cache' => false,
Testing: Mock the facade in tests:
TailwindMerge::shouldReceive('merge')
->once()
->with('expected-classes')
->andReturn('merged-classes');
twMerge('') returns an empty string.twMerge(' p-4 ', 'p-6') → p-6).hover:bg-red-500) are merged like static classes.How can I help you explore Laravel packages today?