DEV Community

Muhammad Hanif
Muhammad Hanif

Posted on • Updated on

Simplify Your Tailwind CSS Workflow with tailwind-fun

If you're a frontend developer working with Tailwind CSS, you know how powerful and versatile it is. However, managing class names in your codebase can quickly become overwhelming, especially when dealing with conditional rendering or dynamically changing styles. That's where the tailwind-fun library comes to the rescue. In this blog post, we'll explore how tailwind-fun can simplify your Tailwind CSS workflow and make your code more readable and maintainable.

What is tailwind-fun?

tailwind-fun is a lightweight JavaScript library designed to streamline the management of Tailwind CSS class names. It provides a fluent API that allows you to easily add, remove, and modify class names based on various conditions and variants. Whether you're handling conditional rendering, hover effects, or applying different styles based on user interactions, tailwind-fun has got you covered.

Simplified and Declarative Class Name Handling

One of the standout features of TWSClass is its declarative approach to class name handling. Let's take a look at an example:

import { TWS } from 'twsclass';

const Component = ({ isHighlighted, isDisabled) => <div className= {TWS('btn')
  .addWhen(isHighlighted, 'bg-yellow-200')
  .removeWhen(isDisabled, 'cursor-not-allowed')}> text</div>
Enter fullscreen mode Exit fullscreen mode

or some more complex example

import { TWS } from "tailwind-fun";

type DateRowProps = { dates: readonly Date[] };

const overlayClass = (
  isSelected: boolean,
  isToday: boolean,
  isSameMonth: boolean
) =>
  TWS("absolute h-[36px] w-[36px] top-[-5.5px] left-[-7.5px] rounded-full")
    .addWhen(isSelected, "bg-selectedBlue")
    .addWhen(isToday, "border-selectedBlue border")
    .addVariants("group-hover", "bg-white z-10");

export const DateRow = consumeDateReducer<DateRowProps>(
  ({ dates, selectedMonth, dispatch, isSelected }) => (
    <div className="flex gap-5 mb-3 ">
      { => (
          onClick={() => dispatch({ type: "UpdateDate", date })}
            TWS("flex-1 grow text-center relative group").addWhen(
              !isSameMonth(selectedMonth, date),
                isSameMonth(selectedMonth, date)
          <span className={TWS("relative group-hover:text-dark").className}>

Enter fullscreen mode Exit fullscreen mode

Handling Hover Effects and Variants

tailwind-fun also provides built-in support for handling hover effects and other Tailwind CSS variants. Let's consider an example where we want to apply a hover effect to a button:

const twsClass = TWS('btn')
  .addVariants('hover:text-white', 'text-blue-500');

const classNames = twsClass.className;
Enter fullscreen mode Exit fullscreen mode

In this case, we use the addHover method to add a hover class name, which applies the bg-blue-500 style when hovering over the button. Additionally, we use the addVariants method to apply the hover:text-white variant, which changes the text color to white on hover.

With tailwind-fun, handling hover effects and other variants becomes straightforward and intuitive. You can easily manage complex class name combinations without sacrificing readability or maintainability.

Composing style using tailwind-fun

you can also compose style for your components like this using tailwind-fun

const button = TWS("flex p-5");
const buttonPrimary = button.addClass("bg-pimrary");
const buttonSecondary = button.addClass("bg-secondary");

// and use in element
<button className={button.className} />
<button className={buttonPrimary.className} />
<button className={buttonSecondary.className} />

Enter fullscreen mode Exit fullscreen mode

but I wouldn't recommend it, because I think the point of using tailwind is to not having to abstract class into component based style. it even better to write tailwind classes into the html directly and to use tailwind-fun sparingly and only if you needed to add logic to your classes. tailwind-fun purpose is more like of rather than any other css library

think of tailwind-fun as a classnames but on steroid, since it more expressive and declarative.

Update (Tailwind-fun 0.2.0)

in the version 0.2.0 tailwind fun adding a pipeable api, you can read about it here. it make you able to write using tailwind-fun like below

import { TWS, addVariants, addWhen, removeWhen  } from 'tailwind-fun';

const pipe = <T>(value: T, ...fns: Function[]) =>
  fns.reduce((prev, next) => next(prev), value);

const buttonClass = ({ primary, secondary, fluid, widthPx }: any) =>
    TWS('block p-5'),
    addWhen(primary, 'bg-primary text-primary'),
    addWhen(secondary, 'bg-secondary'),
    addWhen(fluid, 'w-100'),
    addWhen(Number.isInteger(widthPx), `w-[${widthPx}px]`)

console.log(buttonClass({ primary: true, fluid: true }).className); //block p-5 bg-primary text-primary w-100
console.log(buttonClass({ secondary: true, fluid: true }).className); // block p-5 bg-secondary w-100;
console.log(buttonClass({ primary: true, widthPx: 50 }).className); // block p-5 bg-primary text-primary w-[50px];
Enter fullscreen mode Exit fullscreen mode


The tailwind-fun library provides a powerful yet lightweight solution for managing Tailwind CSS class names in a simplified and declarative manner. By using the fluent API and built-in methods, you can handle conditional rendering, hover effects, and other class name modifications with ease. Say goodbye to convoluted class name manipulation and embrace a cleaner, more maintainable codebase.

To start using tailwind-fun in your projects, simply install the library via npm or include it directly in your codebase. Visit the official documentation for detailed usage instructions and explore the full range of capabilities.

Upgrade your Tailwind CSS workflow with tailwind-fun

Top comments (4)

wahyusa profile image
Wahyu Syamsul A'lam

Interesting, although it may appear a little bit weird for some people.. that's why it's called as declarative , just like naming convention in Laravel.

hanipcode profile image
Muhammad Hanif

yeah I think I should highlight more about it being declarative to not confuse people. thanks for the comment/feedback :D

omar_karim_192f75c9c75bd9 profile image
Omar Karim

Looks like a mess

hanipcode profile image
Muhammad Hanif

thanks for the feedback