Search code examples
htmlcsshtml-selecttailwind-css

Tailwind CSS change text color of placeholder option


I have a project where I need to use a select inside a form. All other type of inputs have a placeholder with a light gray color. The text typed inside the inputs is black.

The select input of the form needs to have the same styling. The default/placeholder value needs to be shown in a dark gray and the real values that the user can select need to be shown in black. But when I try to specify a different color for the first (default/placeholder) option it doesn't use this color. It actually keeps on using the color specified in the select element.

Here is the select inside the element:

 <select
        type="text"
        name="carType"
        id="carType"
        v-model="carType"
        placeholder="Car Type"
        class="my-2 px-4 py-3 border rounded-lg text-black-primary focus:outline-none text-sm"
      >
        <option class="text-gray-400" value="" disabled selected>Select your option</option>
        <option value="volvo">Volvo</option>
        <option value="saab">Saab</option>
        <option value="mercedes">Mercedes</option>
        <option value="audi">Audi</option>
</select>

Solution

  • It can be a tricky one using vanilla CSS too but there is a workaround. If it's a required field, you can add the required attribute to your select element and use the :invalid pseudo class to style it as a placeholder. The idea is that if the first option is used as a placeholder, it's selected and disabled by default, that form field is invalid so you can style it a such.

    In the snippet below I only add a required attribute and style the :invalid class directly, which is not really Tailwind-y, but it works:

    @import url("https://unpkg.com/tailwindcss@^2/dist/tailwind.min.css");
    
    :invalid {
      color: rgba(156, 163, 175, 1);
    }
    <select
      type="text"
      id="carType"
      class="my-2 px-4 py-3 border rounded-lg text-black-primary focus:outline-none text-sm"
      name="carType"
      required
      v-model="carType"
    >
      <option value="" disabled selected>Select your option</option>
      <option value="volvo">Volvo</option>
      <option value="saab">Saab</option>
      <option value="mercedes">Mercedes</option>
      <option value="audi">Audi</option>
    </select>

    Custom Tailwind 2 variants

    The following is only relevant to Tailwind 2, Tailwind 3 has added invalid: utilities

    Although Tailwind has utilities like hover:, focus:, disabled:, etc, unfortunately it doesn't have an invalid: one. If you want to use the invalid:text-gray-400 variant, you need to create a plugin. Luckily, the docs has a nice example which can be used as a base for ours:

    // tailwind.config.js
    const plugin = require('tailwindcss/plugin');
    
    module.exports = {
      variants: {
        textColor: ({ after }) => after(['invalid']),
      },
      plugins: [
        plugin(function ({ addVariant, e }) {
          addVariant('invalid', ({ modifySelectors, separator }) => {
            modifySelectors(({ className }) => {
              return `.${e(`invalid${separator}${className}`)}:invalid`;
            });
          });
        }),
      ],
    };
    

    Now you can use the class as invalid:text-gray-400 in your select element, and get rid of the custom CSS style:

    <select
      type="text"
      id="carType"
      class="my-2 px-4 py-3 border rounded-lg text-black-primary invalid:text-gray-400 focus:outline-none text-sm"
      name="carType"
      required
      v-model="carType"
    >
      <option value="" disabled selected>Select your option</option>
      <option value="volvo">Volvo</option>
      <option value="saab">Saab</option>
      <option value="mercedes">Mercedes</option>
      <option value="audi">Audi</option>
    </select>
    

    Vue conditional classes

    As you're using Vue, a third option would be to use conditional classes. Just toggle between the two classes, text-gray-400 and text-black-primary based on the value of carType.