skip to content

Why Conditional Class Utilities Might Not Be Necessary

A case for using TailwindCSS pseudo-classes instead of conditional class utilities like clsx and classnames.


· 2 min read

Last Updated:


CSS pseudo-class is a keyword added to a selector that specifies a special state of the selected element(s).

MDN Web Docs.

Common pseudo classes include hover, disabled, active.

TailwindCSS has first class support for pseudo class modifiers. This means that:

Every utility class in Tailwind can be applied conditionally by adding a modifier to the beginning of the class name that describes the condition you want to target.

Handling Hover, Focus, And Other States

As I discuss in [[A Design System Worthy Tag Component For Kwicherbelliaken#What is CLSX?]] utilities like clsx and classnames’s job is to:

… make dynamic and conditional className props simpler to work with (especially more so than conditional string manipulation).

classnames README

But they can be abused to apply conditional styles that are already accommodated by TailwindCSS’s support for pseudo class modifiers.

ImproperConditionalStylingComponent.jsx
<Button
isDisabled={isSaveDisabled}
className={classNames(
'text-sm inline-flex justify-center ...',
{ 'cursor-not-allowed bg-opacity-50': isSaveDisabled }
)}
>

A simpler approach, and one that leverages TailwindCSS’s disabled pseudo class modifiers, which makes the need for the classNames utility redundant.

ImproperConditionalStylingComponent.jsx
<Button
isDisabled={isSaveDisabled}
className="... disabled:cursor-not-allowed disabled:bg-opacity-50"
>

But this is not to say they don’t have an application and aren’t useful. Say we now needed to handle a loading state for this Button, well this is where this utility becomes very helpful:

ImproperConditionalStylingComponent.jsx
<Button
isDisabled={isSaveDisabled}
className={classNames(
'... disabled:cursor-not-allowed disabled:bg-opacity-50',
{ 'bg-blue-50 animate': isLoading }
)}
>

There are of course more real world examples to be found:

ModalExample.jsx
<Modal
className={({ isEntering, isExiting }) =>
classNames(
"tw-w-full tw-max-w-md tw-overflow-hidden tw-rounded-2xl tw-p-6 tw-text-left tw-align-middle",
{
"tw-animate-in tw-zoom-in-95 tw-ease-out tw-duration-300": isEntering,
"tw-animate-out tw-zoom-out-95 tw-ease-in tw-duration-200": isExiting,
},
)
}
/>