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 Php Laravel Package

gehrisandro/tailwind-merge-php

Merge Tailwind CSS class strings in PHP with automatic conflict resolution (last class wins), ported from tailwind-merge. Supports Tailwind v3.0–v3.4, configurable and cacheable. Requires PHP 8.1+.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package via Composer:

composer require gehrisandro/tailwind-merge-php

First Use Case: Merge conflicting Tailwind classes in a Blade template or Livewire component:

use TailwindMerge\TailwindMerge;

// In a Blade view or component method
$mergedClasses = TailwindMerge::instance()->merge('text-red-500', 'text-blue-500');
// Output: 'text-blue-500'

Where to Look First:

  1. Basic Usage: Review the Usage section in the README for common scenarios (conflicts, breakpoints, dark mode, etc.).
  2. Configuration: Check if your custom Tailwind config requires adjustments (e.g., custom font sizes, colors).
  3. Caching: Enable PSR-16 caching for performance-critical applications (e.g., Livewire).

Implementation Patterns

1. Blade Directives (Reusable Logic)

Create a custom Blade directive to merge classes globally:

// In AppServiceProvider@boot()
Blade::directive('merge', function ($expression) {
    return "<?php echo TailwindMerge::instance()->merge({$expression}); ?>";
});

// Usage in Blade:
<div class="@merge(['bg-red-500', 'bg-blue-500'])">Merged!</div>

2. Livewire Component Integration

Merge classes dynamically in Livewire properties:

use Livewire\Component;
use TailwindMerge\TailwindMerge;

class ButtonComponent extends Component
{
    public $baseClasses = 'px-4 py-2 rounded';
    public $variant = 'primary'; // 'primary', 'secondary'

    public function getMergedClassesProperty()
    {
        return TailwindMerge::instance()->merge(
            $this->baseClasses,
            $this->variant === 'primary'
                ? 'bg-blue-500 hover:bg-blue-600 text-white'
                : 'bg-gray-500 hover:bg-gray-600 text-gray-800'
        );
    }

    public function render()
    {
        return view('livewire.button', [
            'classes' => $this->mergedClassesProperty,
        ]);
    }
}

3. Dynamic Class Merging in APIs/Emails

Merge classes based on runtime data (e.g., user roles, tenant themes):

use TailwindMerge\TailwindMerge;

class EmailService
{
    public function generateButtonClasses(string $role): string
    {
        $base = 'px-4 py-2 rounded font-medium';
        $roleClasses = match ($role) {
            'admin' => 'bg-red-500 text-white',
            'user' => 'bg-blue-500 text-white',
            default => 'bg-gray-500 text-gray-800',
        };

        return TailwindMerge::instance()->merge($base, $roleClasses);
    }
}

4. Form Request Validation Classes

Merge error/state classes dynamically:

use Illuminate\Validation\Validator;
use TailwindMerge\TailwindMerge;

Validator::extend('custom-classes', function ($attribute, $value, $parameters, $validator) {
    $merged = TailwindMerge::instance()->merge(
        'border border-gray-300',
        $validator->errors()->has($attribute) ? 'border-red-500' : 'border-green-500'
    );
    // Use $merged in your form logic...
});

5. View Composers for Global Merging

Apply merging to all views via a composer:

// In AppServiceProvider@boot()
View::composer('*', function ($view) {
    $view->with('mergedClasses', function () {
        return TailwindMerge::instance()->merge(
            'text-gray-800 dark:text-gray-200',
            request()->user()?->prefersDarkMode() ? 'bg-gray-900' : 'bg-white'
        );
    });
});

// In Blade:
<body class="{{ $mergedClasses }}">

6. Testing Class Merging

Assert merged classes in PHPUnit:

use TailwindMerge\TailwindMerge;
use Tests\TestCase;

class TailwindMergeTest extends TestCase
{
    public function testMergeConflicts()
    {
        $merged = TailwindMerge::instance()->merge('p-4 px-6', 'p-8');
        $this->assertEquals('px-6', $merged);
    }

    public function testDarkMode()
    {
        $merged = TailwindMerge::instance()->merge(
            'text-black',
            'dark:text-white dark:text-gray-700'
        );
        $this->assertEquals('text-black dark:text-gray-700', $merged);
    }
}

Gotchas and Tips

Pitfalls

  1. Custom Tailwind Config Mismatches

    • If your tailwind.config.js uses non-standard class names (e.g., custom colors like bg-custom-red), you must update the classGroups configuration:
      TailwindMerge::factory()->withConfiguration([
          'classGroups' => [
              'colors' => [
                  ['bg' => ['custom-red']],
                  ['text' => ['custom-red']],
              ],
          ],
      ])->make();
      
    • Debug Tip: Compare your tailwind.config.js with the original package’s config docs.
  2. Arbitrary Values ([...]) Overrides

    • Arbitrary classes (e.g., bg-[var(--color)]) always win over standard Tailwind classes. If this isn’t desired, avoid mixing them or use the !important modifier (!bg-red-500).
    • Fix: Explicitly order classes to prioritize standard Tailwind:
      TailwindMerge::instance()->merge('bg-[var(--color)]', '!bg-red-500');
      // Result: '!bg-red-500' (if !important is supported in your build)
      
  3. Caching Stale Configurations

    • If you update the classGroups config, clear the cache:
      php artisan cache:clear
      
    • Tip: Use a cache key tied to your Tailwind config version to invalidate only when needed.
  4. Non-Tailwind Classes

    • Non-Tailwind classes (e.g., custom-class) are preserved but may cause unexpected behavior if they conflict with Tailwind’s internal logic. Test thoroughly.
  5. PHP 8.1+ Requirement

    • The package will not work on PHP <8.1. Verify your environment:
      php -v
      
  6. Performance with Large Class Lists

    • Merging hundreds of classes (e.g., in a complex component) may introduce latency. Mitigate by:
      • Caching the merged result (PSR-16).
      • Pre-merging static classes in your Blade templates.
  7. Dark Mode and State Conflicts

    • Dark mode classes (dark:...) are merged last, so later classes override earlier ones. Example:
      TailwindMerge::instance()->merge('text-white', 'dark:text-black');
      // Result: 'text-white dark:text-black' (not 'dark:text-black')
      
    • Fix: Reorder classes or use !important if needed.

Debugging Tips

  1. Inspect Raw Merging Logic

    • Temporarily enable debug output to see intermediate steps:
      $tw = TailwindMerge::factory()->withDebug(true)->make();
      $merged = $tw->merge('p-4 px-6');
      // Check $tw->getDebugLog() for details.
      
  2. Validate Tailwind Config

    • Run Tailwind’s CLI to ensure your config is correct:
      npx tailwindcss -i input.css -o output.css --content ./resources/views/**/*.blade.php
      
  3. Test Edge Cases

    • Common edge cases to test:
      • Conflicting breakpoints (lg:p-4 md:p-6).
      • Mixed !important and arbitrary values (!text-red-500 bg-[var(--color)]).
      • Nested variants (group-hover:text-red-500 hover:text-blue-500).
  4. Fallback for Unsupported Classes

    • If a class isn’t merged as expected, it might not be in the default config. Workaround:
      $tw = TailwindMerge::factory()->withConfiguration([
          'classGroups' => [
              'custom' => [
                  ['your-prefix' => ['your-class']],
              ],
          ],
      ])->make();
      

Extension Points

  1. Custom Validators
    • Extend the package by adding custom validators for your arbitrary values:
      use TailwindMerge\Validators\ArbitraryValidator;
      
      class CustomArbitraryValidator extends ArbitraryValidator
      {
          protected function getSupportedLabels(): array
          {
              return array_merge(parent::getSupportedLabels
      
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.
codraw/framework-extra-bundle
codraw/messenger
codraw/security
codraw/mailer
codraw/contracts
codraw/profiling
codraw/dependency-injection
codraw/tester
codraw/core
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony