Cixel

Tailwind CSS v4: Functional Utilities

5 min read
Tailwind CSS v4: Functional Utilities

Tailwind CSS just released version 4, and it's a big one! This release is much more focused on using CSS standards over JavaScript, which have evolved over recent years. The switch to CSS-first has significantly improved developer performance with much faster build times. Plus many quality of life and minor tweaks.

One of the most exciting features in this release: functional utilities can now be written in CSS instead of JavaScript! Let's dive into how to use and create your own functional utilities.

1. Migrating to Tailwind CSS v4

Before you start using version 4, you'll need to upgrade your project. The Tailwind team has made this process as easy as possible with a new upgrade tool. If you're currently using v3, you can upgrade your project to v4 by running the command:

Terminal
npx @tailwindcss/upgrade@next
Tip
Having trouble migrating? Check out Tailwind's upgrade guide for more information.

2. What is a functional utility?

Functional utilities are a powerful feature in Tailwind CSS, they allow you to pass values and arbitrary values to your utilities. This allows you to create dynamic styles that can be re-used throughout your project.

Tailwind offers some functional utilities out of the box, such as:

  • text-* — For styling font sizes
  • border-* — For styling borders with width and color
  • rounded-* — For styling border radius

What has changed in v4?

In previous versions of Tailwind CSS, to create a custom utility you would need to use JavaScript. However, in v4, you can now create custom utilities using CSS syntax!

Creating a functional utility in previous versions looked something like this:

tailwind.config.js
import plugin from 'tailwindcss/plugin';
 
plugins: [
  plugin(({ matchUtilities, theme }) => {
    matchUtilities(
      {
        'text-stroke': (width) => ({
          WebkitTextStrokeWidth: width
        })
      },
      {
        type: ['line-width', 'any'],
        values: theme('borderWidth')
      }
    )
  })
];

Here's how you can do this in v4:

CSS
@utility text-stroke-* {
  -webkit-text-stroke-width: --value(integer)px;
  -webkit-text-stroke-width: --value([*]);
}

Why use functional utilities?

  • Flexibility: Create dynamic styles without writing custom CSS
  • Type-safe: Built-in validation for values and colors
  • Less code: Reduce the amount of CSS you write
  • Dev experience: Great autocomplete support with Tailwind CSS IntelliSense
Caution
Just because you can add a specific functional utility, doesn't always mean you should.
Be mindful to not add too much complexity to your project.

Understanding --value() and --modifier()

When creating functional utilities, it's important to understand the two key functions:

  • --value(): Uses the first value passed into the functional utility.
    • text-*: The * is the value passed to the utility, such as text-2xl or text-white
CSS — Value example
/* Usage: typography-2
                     ↑ value
                    
                    ↓ value placeholder */
@utility typography-* {
  font-size: --value(integer)rem;
  /*                  ↑ Requires value to be an integer */
}
  • --modifier(): Uses the second value passed into the functional utility, following a /.
    • text-red/*: The * is the modifier, which can be used to specify a color, such as text-red/80.
CSS — Modifier example
/* Usage: typography-2/red
                        ↑ modifier */
@theme {
  --color-red: #ff0000;
}
 
@utility typography-* {
  font-size: --value(integer)rem;
  color: --modifier(--color-*);
  /*                  ↑ Requires modifier to be a specified color */
}
Note
If no modifier is passed, any declaration depending on a modifier is ignored.
In this case the color would not be applied.

3. Creating a functional utility

Now that we understand what functional utilities are and why to use them, let's explore creating one. While Tailwind's built-in utilities are great, the real power of v4 comes from being able to craft custom utilities that fit your specific needs.

Let's look at an example — creating a text-stroke-* utility, similar to Tailwind's border-* utility. We'll build this step by step to explore how values, colors, and modifiers work together.

Basic utility

First, let's create a basic utility that adds a stroke to text OR a color, depending on the value passed.

CSS
/* Usage: text-stroke-2 text-stroke-white */
 
@utility text-stroke-* {
  -webkit-text-stroke-width: --value(integer)px;
  -webkit-text-stroke-color: --value(--color-*);
}

Supporting arbitrary values

We're off to a good start, but we can make this utility more flexible. To do this, we can add support for arbitrary widths and colors. Arbitrary values are enclosed in square brackets []. This allows us to pass any value we want, such as a color or a width.

CSS
/* Usage: text-stroke-[2px] text-stroke-[green] */
 
@utility text-stroke-* {
  -webkit-text-stroke-width: --value(integer)px;
  -webkit-text-stroke-width: --value([*]);
  -webkit-text-stroke-color: --value(--color-*, [color]);
}

Using a modifier

Let's add the option to use a modifier. This way we can more easily add a text stroke color at the same time! Modifiers are a great way to simplify your code.

CSS
/* Usage: text-stroke-2/white */
 
@utility text-stroke-* {
  -webkit-text-stroke-width: --value(integer)px;
  -webkit-text-stroke-width: --value([*]);
  -webkit-text-stroke-color: --value(--color-*, [color]);
  -webkit-text-stroke-color: --modifier(--color-*, [color]);
}

As you can see, we can easily create useful functional utilities with Tailwind CSS, and we don't have to touch JavaScript at all, it truly is paradise. 🏝️

Tip
Using Tailwind CSS IntelliSense allows you to easily autocomplete --value() and --modifier() function parameters for a smoother development experience.

Final thoughts

The new way of creating functional utilities in Tailwind CSS v4 makes it easier than ever to create powerful and flexible styles for your website. It's definitely worth making the move to Tailwind CSS v4 if you haven't already!

Next Post

4 Reasons Why You Need a Website

4 Reasons Why You Need a Website

Is your business missing out? Here's 4 reasons you need a website to attract more customers and stay competitive.

4 min read