In order to use Tailwind CSS for styling the input slider's track and thumb, I have to rely on two different pseudo elements (WebKit and Mozilla), which results in code duplication.
::-webkit-slider-runnable-track
for Chrome, Edge, Opera, Safari::-moz-range-track
- for Firefox::-webkit-slider-thumb
for Chrome, Edge, Opera, Safari::-moz-range-thumb
- for FirefoxHowever, since these selectors are not standardized, it may be necessary to apply different styles for each system separately.
It is possible to implement this with arbitrary values, but the code becomes very long and unreadable.
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<input
type="range"
class="
m-5 appearance-none w-[20em] h-[2em] outline-none overflow-hidden rounded
/* Track for webkit */
[&::-webkit-slider-runnable-track]:bg-slate-300
[&::-webkit-slider-runnable-track]:h-full
[&::-webkit-slider-runnable-track]:rounded
/* Track for moz */
[&::-moz-range-track]:bg-slate-300
[&::-moz-range-track]:h-full
[&::-moz-range-track]:rounded
/* Thumb for webkit */
[&::-webkit-slider-thumb]:h-full
[&::-webkit-slider-thumb]:w-[8px]
[&::-webkit-slider-thumb]:bg-blue-500
[&::-webkit-slider-thumb]:[box-shadow:_-20em_0_0_20em_black]
/* Custom for webkit */
[&::-webkit-slider-thumb]:appearance-none
/* Thumb for moz */
[&::-moz-range-thumb]:h-full
[&::-moz-range-thumb]:w-[8px]
[&::-moz-range-thumb]:bg-blue-500
[&::-moz-range-thumb]:[box-shadow:_-20em_0_0_20em_black]
/* Custom for moz */
[&::-moz-range-thumb]:border-0
[&::-moz-range-thumb]:rounded-none
"
/>
I tried creating a custom variant, but it seems it doesn't work:
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<style type="text/tailwindcss">
@custom-variant slider-track (&::-webkit-slider-runnable-track, &::-moz-range-track));
</style>
<input
type="range"
class="
m-5 appearance-none w-[20em] h-[2em] outline-none overflow-hidden rounded
/* Track for webkit & moz */
slider-track:bg-slate-300
slider-track:h-full
slider-track:rounded
/* Thumb for webkit */
[&::-webkit-slider-thumb]:h-full
[&::-webkit-slider-thumb]:w-[8px]
[&::-webkit-slider-thumb]:bg-blue-500
[&::-webkit-slider-thumb]:[box-shadow:_-20em_0_0_20em_black]
/* Custom for webkit */
[&::-webkit-slider-thumb]:appearance-none
/* Thumb for moz */
[&::-moz-range-thumb]:h-full
[&::-moz-range-thumb]:w-[8px]
[&::-moz-range-thumb]:bg-blue-500
[&::-moz-range-thumb]:[box-shadow:_-20em_0_0_20em_black]
/* Custom for moz */
[&::-moz-range-thumb]:border-0
[&::-moz-range-thumb]:rounded-none
"
/>
How can I make the variants in class names more readable, and how can I eliminate code duplication this way?
You're on the right track - using custom variants, you can make the values written as arbitrary values more readable. Not only single-line custom variants can be created, but much more complex ones as well. In this case, the styles passed to the variant need to be declared twice: once for WebKit and once for Mozilla, and these cannot be merged.
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<style type="text/tailwindcss">
@custom-variant slider-track {
&::-webkit-slider-runnable-track {
@slot;
}
&::-moz-range-track {
@slot;
}
}
@custom-variant slider-thumb {
&::-webkit-slider-thumb {
@slot;
}
&::-moz-range-thumb {
@slot;
}
}
</style>
<input
type="range"
class="
m-5 appearance-none w-[20em] h-[2em] outline-none overflow-hidden rounded
slider-track:h-full
slider-track:bg-slate-300 slider-track:rounded
slider-thumb:h-full slider-thumb:w-[8px]
slider-thumb:bg-sky-500 slider-thumb:[box-shadow:_-20em_0_0_20em_black]
"
/>
Note: The example is not perfect yet, as it lacks Mozilla-specific and WebKit-specific styling.
After that, we can create additional custom variant - with consistent naming - that apply styles specifically for WebKit or Mozilla only.
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<style type="text/tailwindcss">
@custom-variant slider-track {
&::-webkit-slider-runnable-track {
@slot;
}
&::-moz-range-track {
@slot;
}
}
@custom-variant slider-track--webkit (&::-webkit-slider-runnable-track);
@custom-variant slider-track--moz (&::-moz-range-track);
@custom-variant slider-thumb {
&::-webkit-slider-thumb {
@slot;
}
&::-moz-range-thumb {
@slot;
}
}
@custom-variant slider-thumb--webkit (&::-webkit-slider-thumb);
@custom-variant slider-thumb--moz (&::-moz-range-thumb);
</style>
<input
type="range"
class="
m-5 appearance-none w-[20em] h-[2em] outline-none overflow-hidden rounded
slider-track:h-full
slider-track:bg-slate-300 slider-track:rounded
slider-thumb:h-full slider-thumb:w-[8px]
slider-thumb:bg-sky-500 slider-thumb:[box-shadow:_-20em_0_0_20em_black]
slider-thumb--webkit:appearance-none
slider-thumb--moz:border-0 slider-thumb--moz:rounded-none
"
/>