Search code examples
phpcsslaraveltailwind-css

Laravel components rendered and TailwindCSS v3


I have this views/components/flash-status-message component:

@php use App\Enums\FlashStatuses; @endphp
@foreach(FlashStatuses::values() as $type)
    @if(Session::has($type))
        @php $color = FlashStatuses::from($type)->color(); @endphp
        <div id="flash-message" class="fixed top-4 right-4 z-50">
            <div class="flex items-center bg-{{$color}}-100 border-l-4 border-{{$color}}-500 text-{{$color}}-700 px-2 py-4 rounded-lg shadow-lg max-w-sm lg:max-w-xs">
                <div class="ml-3">
                    <p class="text-sm font-semibold text-{{$color}}-700">{{ __(ucfirst($type)) }}!</p>
                    <p class="text-sm text-{{$color}}-700">{{ Session::get($type) }}</p>
                </div>
                <div class="bg-{{$color}}-100"></div>
                <button id="flash-message-close"
                        class="ml-auto text-{{$color}}-500 hover:text-{{$color}}-700 focus:outline-none">
                    <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"
                         xmlns="http://www.w3.org/2000/svg">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
                              d="M6 18L18 6M6 6l12 12"></path>
                    </svg>
                </button>
            </div>
        </div>
    @endif
@endforeach

@vite('resources/js/flash-message.js')

and in layouts/default.blade.php I use my component

<x-flash-status-message />

HTML that I have:

<div class="flex items-center bg-green-100 border-l-4 border-green-500 text-green-700 px-2 py-4 rounded-lg shadow-lg max-w-sm lg:max-w-xs">
                <div class="ml-3">
                    <p class="text-sm font-semibold text-green-700">Success!</p>
                    <p class="text-sm text-green-700">test</p>
                </div>
                <div class="bg-green-100"></div>
                <button id="flash-message-close" class="ml-auto text-green-500 hover:text-green-700 focus:outline-none">
                    <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
                    </svg>
                </button>
            </div>

As you can see I use TailwindCSS v3, and it seems like colors depend of status(in this case success) rendered corretly but in reality I have black color(TailwindCSS default), and it seems like colors aren't applied correctly. I'm wondering why, probably because of @foreach or component nature or whatever, so any thought will be appreciated. Thanks in advance!

I was expecting that I have flash message with color that were in html of that component. Unfortunately I didn't have that.


Solution

  • I faced the same issue here's what I found out.

    The issue lies in how Tailwind CSS handles class names dynamically. Tailwind generates the necessary CSS classes at build time, meaning if you use a dynamic value like bg-{{$color}}-100, it won't be recognized since Tailwind doesn't know all possible values at build time.

    Here's a few work-arounds: (Apologies for the code examples, I am using React, but the underlying aspect remains the same)

    1. Using Template Literals with Full Class Name

    Tailwind requires the full class names to be present in the code. When dynamically changing classes, you can use conditional logic to dynamically set the class names.

    However, this will still only work for the specific colors that Tailwind knows at build time.

    <Link
      to="/home"
      className={`text-${appTheme === 'blue' ? 'blue' : appTheme}-500 mb-0 silkscreen-regular px-0 py-2 rounded-md`}
      aria-current="page"
    >
    

    2. Ensure Tailwind Classes Are Generated for All Themes

    If you're using multiple themes (like blue, red, green, etc.), ensure that all the theme color classes (text-blue-500, text-red-500, etc.) are included in your final CSS. Tailwind needs to see these class names to generate the corresponding styles.

    You can achieve this by using a theme object in your Tailwind configuration.

    3. Recommended Approach with Conditional Classes

    You can explicitly create a map of themes and dynamically set the class based on the value

    const themeClasses = {
        blue: 'text-blue-500',
        red: 'text-red-500',
        green: 'text-green-500',
        // add more colors as needed
    };
    
    <Link
      to="/home"
      className={`${themeClasses[appTheme] || 'text-blue-500'} mb-0 silkscreen-regular px-0 py-2 rounded-md`}
      aria-current="page"
    >
      Home
    </Link>
    

    4. Approach with Tailwind's @apply

    If you want more flexibility, you can define your own color schemes in Tailwind’s config file (tailwind.config.js), allowing you to have more control over the theme and apply styles dynamically.

    Configure the colors on the tailwind.config.js

    module.exports = {
      theme: {
        extend: {
          colors: {
            'theme-blue': '#1DA1F2',
            'theme-red': '#E0245E',
            'theme-green': '#17BF63',
          },
        },
      },
      // other config...
    };
    

    Use the dynamic class based on a theme or predefined color

    <Link
      to="/home"
      className={`text-theme-${appTheme} mb-0 silkscreen-regular px-0 py-2 rounded-md`}
      aria-current="page"
    >
      Home
    </Link>