Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Tailwind Merge Laravel Laravel Package

gehrisandro/tailwind-merge-laravel

Merge Tailwind CSS classes in Laravel and automatically resolve conflicts (later classes win). Ideal for Blade components and directives. PHP/Laravel port of tailwind-merge. Supports Tailwind v3.0–v3.3 (Laravel 10+).

View on GitHub
Deep Wiki
Context7
## Getting Started

### Minimal Setup
1. **Installation**:
   ```bash
   composer require gehrisandro/tailwind-merge-laravel

Publish the config (optional but recommended for customization):

php artisan vendor:publish --provider="TailwindMerge\Laravel\TailwindMergeServiceProvider"
  1. First Use Case: In a Blade component, replace $attributes->class with $attributes->twMerge() to merge classes dynamically:

    <!-- components/Button.blade.php -->
    <button {{ $attributes->twMerge('px-4 py-2 rounded bg-blue-500 hover:bg-blue-600') }}>
        {{ $slot }}
    </button>
    

    Usage in a view:

    <x-button class="text-white font-bold">Click Me</x-button>
    

    Output:

    <button class="px-4 py-2 rounded bg-blue-500 hover:bg-blue-600 text-white font-bold">Click Me</button>
    
  2. Key Files to Review:

    • config/tailwind-merge.php: Customize prefixes, class groups, or disable the Blade directive.
    • app/View/Components/ or your Blade component directory: Start integrating twMerge into existing components.

Implementation Patterns

1. Blade Component Integration

  • Default Pattern: Replace $attributes->class with $attributes->twMerge('base-classes') in component definitions.
    <div {{ $attributes->twMerge('p-4 border rounded-lg') }}>
        {{ $slot }}
    </div>
    
  • Multi-Element Merging: Use twMergeFor() for nested elements (e.g., icons, badges) with withoutTwMergeClasses() to avoid attribute pollution:
    <button {{ $attributes->withoutTwMergeClasses()->twMerge('px-4 py-2') }}>
        <svg {{ $attributes->twMergeFor('icon', 'h-5 w-5') }} ...></svg>
        {{ $slot }}
    </button>
    
    Usage:
    <x-button class="bg-red-500" class:icon="text-white">Delete</x-button>
    

2. Dynamic Class Merging in Views

  • Blade Directive: Use @twMerge() for ad-hoc merging in views:
    <div @twMerge('text-lg', 'text-red-500', 'font-bold')>Dynamic Text</div>
    
  • Facade/Helper: Merge classes in PHP logic (e.g., controllers, livewire components):
    use TailwindMerge\Laravel\Facades\TailwindMerge;
    $mergedClasses = TailwindMerge::merge('bg-gray-100', 'hover:bg-gray-200');
    
    Or via helper:
    $mergedClasses = twMerge('bg-gray-100', 'hover:bg-gray-200');
    

3. Livewire/Alpine Integration

  • Livewire: Merge classes dynamically in component properties:
    public $buttonClasses = 'px-4 py-2 rounded';
    public $activeButtonClasses = 'bg-green-500 text-white';
    
    Blade:
    <button class="{{ twMerge($buttonClasses, $active ? $activeButtonClasses : '') }}">
        {{ $slot }}
    </button>
    
  • Alpine.js: Use x-bind:class with merged classes:
    <div x-data="{ isOpen: false }"
         :class="twMerge('p-4', isOpen ? 'bg-blue-100' : 'bg-gray-100')">
        <!-- ... -->
    </div>
    

4. Theming Systems

  • Dark Mode: Merge dark variants dynamically:
    <div class="{{ twMerge('bg-white', 'dark:bg-gray-800', 'text-black', 'dark:text-white') }}">
        Content
    </div>
    
  • Brand Theming: Override base classes per tenant/user:
    $tenantClasses = Tenant::find($id)->theme_classes;
    $merged = twMerge('bg-primary', $tenantClasses);
    

5. Custom Tailwind Configs

  • Extend classGroups in config/tailwind-merge.php for custom utilities:
    'classGroups' => [
        'custom' => [
            ['bg' => ['brand-primary', 'brand-secondary']],
            ['text' => ['brand-text']],
        ],
    ],
    
  • Example usage:
    <div class="{{ twMerge('bg-brand-primary', 'hover:bg-brand-secondary') }}">...</div>
    

Gotchas and Tips

Pitfalls

  1. Attribute Pollution:

    • Issue: Using $attributes->merge() instead of twMerge will duplicate classes.
    • Fix: Always use twMerge or twMergeFor in components.
    • Workaround: Clear existing classes with withoutTwMergeClasses():
      {{ $attributes->withoutTwMergeClasses()->twMerge('...') }}
      
  2. Non-Tailwind Classes:

    • Issue: Arbitrary classes (e.g., class="custom-class") may not merge predictably.
    • Fix: Place them first in the merge chain:
      <div class="{{ twMerge('custom-class', 'p-4') }}">...</div>
      
  3. Caching Quirks:

    • Issue: Merged classes in Blade directives (@twMerge) are not cached by default.
    • Fix: Cache manually in controllers or use Livewire/Alpine for dynamic updates.
  4. Tailwind Version Mismatch:

    • Issue: The package supports Tailwind v3.0–v3.3. Using v2.x or v4.x may break merging.
    • Fix: Update Tailwind or check the changelog for compatibility.
  5. Nested twMergeFor:

    • Issue: Deeply nested twMergeFor calls can lead to attribute name collisions.
    • Fix: Use unique suffixes:
      <div {{ $attributes->twMergeFor('wrapper', 'p-4') }}>
          <button {{ $attributes->twMergeFor('button', 'px-2') }}>...</button>
      </div>
      
      Usage:
      <x-component class:wrapper="bg-gray-100" class:button="bg-blue-500">...</x-component>
      

Debugging Tips

  1. Inspect Merged Output: Use dd(twMerge('class1', 'class2')) to debug conflicts in Tinker or a route.

  2. Validate Tailwind Config: If merging fails, verify your tailwind.config.js aligns with the package’s assumptions (e.g., no conflicting custom classes).

  3. Check for Typos: Arbitrary values (e.g., z-[999]) must match Tailwind’s syntax exactly.

  4. Disable Directive Temporarily: Set 'blade_directive' => null in config/tailwind-merge.php to isolate issues.

Performance Tips

  1. Cache Merged Classes: Cache results in Livewire/Alpine or controllers for dynamic components:

    // Livewire component
    public $mergedClasses;
    public function mount() {
        $this->mergedClasses = twMerge('base', 'dynamic');
    }
    
  2. Avoid Over-Merging: Merge only necessary classes in loops or large datasets to reduce overhead.

Extension Points

  1. Custom Merge Logic: Extend the underlying TailwindMerge\Laravel\TailwindMerge class to add pre/post-processing:

    // app/Providers/AppServiceProvider.php
    use TailwindMerge\Laravel\TailwindMerge;
    
    public function boot() {
        TailwindMerge::macro('customMerge', function ($classes) {
            return TailwindMerge::merge($classes, '!important-class');
        });
    }
    
  2. Add New Class Groups: Extend config/tailwind-merge.php for project-specific utilities:

    'classGroups' => [
        'app' => [
            ['btn' => ['btn-primary', 'btn-secondary']],
            ['spacing' => ['gap-1', 'gap-2']],
        ],
    ],
    
  3. Integrate with View Composers: Pre-merge classes globally in AppServiceProvider:

    public function boot() {
        view()->composer('*', function ($view) {
            $view->with('mergedClasses', twMerge('global-base', 'global-variant'));
        });
    }
    

Common Edge Cases

| Scenario | Solution | |-----------------------------------

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope
anil/file-picker
broqit/fields-ai