Tailwind CSS v3.2 updates Dynamic breakpoints, multi-config, and container queries and many more

Tailwind CSS v3.2 updates Dynamic breakpoints, multi-config, and container queries and many more

Well, Tailwind is a utility-first CSS framework packed with classes like flex, pt-4, text-center and rotate-90 that can be composed to build any design, directly in your markup. Tailwind CSS v3.2 is here with an absolutely massive amount of new stuff, including support for dynamic breakpoints, multiple config files in a single project, nested groups, parameterized variants, container queries, and more.

1. Multiple config files in one project using @config

Tailwind added a new @config directive that you can use in a CSS file to specify which Tailwind CSS config to use for that file.

./styles/admin.css

@config "./tailwindcss.admin.config.js";
@tailwind base;
@tailwind components;
@tailwind utilities;

./styles/client.css

@config "./tailwind.client.config.js";
@tailwind base;
@tailwind components;
@tailwind utilities;

This makes it a lot easier to build multiple stylesheets in a single project that have separate Tailwind configurations. For example, you might have one config file for the customer-facing part of your site, and another config for the admin/backend area.

2. Browser-support-based styling with supports-*

There are some CSS properties that are not support by default in all the browser, like display: grid. In tailwind v3.2 you can conditionally style a page based on whether a certain feature is supported in the user’s browser with the supports-[...] variant, which generates @supports rules under the hood.

→ Example:

<div class="flex supports-[display:grid]:grid ...">
  <!-- your others code... -->
</div>

The supports-[anything] variant takes anything you want in the square brackets.

3. ARIA attribute variants

In tailwindscss v3.2 you can now conditionally style things based on ARIA attributes with the new aria-* variants.

For example, you can update the background color of an element based on whether the aria-checked state is true

→ Example

<span class="bg-gray-600 aria-checked:bg-blue-600" aria-checked="true" role="checkbox">
  <!-- your other code -->
</span>

By default, most of the common area-attributes are true

You can customize like that

module.exports = {
  theme: {
    extend: {
      aria: {
        asc: 'sort="ascending"',
        desc: 'sort="descending"',
      },
    },
  },
};

4. Data attribute variants

As like AREA attribute, you can now conditionally style things based on data attributes with the new data-* variants.

→ Here is an example

<!-- Will apply -->
<div data-size="large" class="data-[size=large]:p-8">
  <!-- ... -->
</div>

<!-- Will not apply -->
<div data-size="medium" class="data-[size=large]:p-8">
  <!-- ... -->
</div>

<!-- Generated CSS -->
<style>
  .data-\[size\=large\]\:p-8[data-size="large"] {
    padding: 2rem;
  }
</style>

5. Max-width and dynamic breakpoints

There is a new max-* variant that lets you apply max-width media queries based on your configured breakpoints. As a general rule, I would still recommend using min-width breakpoints personally, but this feature does unlock one useful workflow benefit, which is not having to undo some style at a different breakpoint.

<div class="max-lg:p-8">
  <!-- Will apply `p-8` until the `lg` breakpoint kicks in -->
</div>

<div class="md:sr-only xl:not-sr-only">
  <!-- ... -->
</div>

5. Dynamic group- and peer- variants

It’s now possible to create custom group-* and peer-* variants on the fly by passing your own selector to be “groupified” or “peerified” between square brackets:

HTML

<div class="group is-published">
  <div class="hidden group-[.is-published]:block">
    Published
  </div>
</div>

Generated CSS

.group.is-published .group-\[\.is-published\]\:block {
  display: block;
}

For more control, you can use the & character to mark where .group or .peer should end up in the final selector relative to the selector you are passing in: HTML

<div>
  <input type="text" class="peer" />
  <div class="hidden peer-[:nth-of-type(3)_&]:block">
    <!-- ... -->
  </div>
</div>

Generated CSS

:nth-of-type(3) .peer ~ .peer-\[\:nth-of-type\(3\)_\&\]\:block {
  display: block;
}

7. Dynamic variants with matchVariant

You’ve probably noticed this new variant-[...] syntax in a lot of these new features — this is all powered by a new matchVariant plugin API that makes it possible to create what tailwinds calling “dynamic variants”.

→ Here’s an example of creating a placement-* variant for some imaginary tooltip library that uses a data-placement attribute to tell you where the tooltip is currently positioned:

let plugin = require("tailwindcss/plugin");

module.exports = {
  // ...
  plugins: [
    plugin(function ({ matchVariant }) {
      matchVariant(
        "placement",
        (value) => {
          return `&[data-placement=${value}]`;
        },
        {
          values: {
            t: "top",
            r: "right",
            b: "bottom",
            l: "left",
          },
        }
      );
    }),
  ],
};

The variant defined above would give you variants like placement-t and placement-b, but would also support the arbitrary portion in square brackets, so if this imaginary tooltip library had other potential values that you didn’t feel the need to create built-in values for, you could still do stuff like this:

<div class="placement-[top-start]:mb-2 ...">
  <!-- ... -->
</div>

When defining a custom variant with this API, it’s often important that you have some control over which order the CSS is generated in to make sure each class has the right precedence with respect to other values that come from the same variant. To support this, there’s a sort function you can provide when defining your variant:

matchVariant("min", (value) => `@media (min-width: ${value})`, {
  sort(a, z) {
    return parseInt(a) - parseInt(z);
  },
});

8. Nested group and multiple peer support using variant modifiers

Sometimes you can run into problems when you have multiple group chunks nested within each other because Tailwind has no real way to disambiguate between them.

To solve this, we’re adding support for variant modifiers, which are a new dynamic chunk that you can add to the end of a variant (inspired by our optional opacity modifier syntax) that you can use to give each group/peer your own identifier.

Here’s what it looks like:

<div class="group/sidebar ...">
  <!-- ... -->
  <div class="group/navitem ...">
    <a
      href="#"
      class="opacity-50 group-hover/sidebar:opacity-75 group-hover/navitem:bg-black/75"
    >
      <!-- ... -->
    </a>
  </div>
  <!-- ... -->
</div>

This lets you give each group a clear name that makes sense for that context on the fly, and Tailwind will generate the necessary CSS to make it work.

9. Container queries

I can barely believe it but container queries are finally real and the browser support is dangerously close to making these ready for production — in fact if you’re building an Electron app you could use these today.

Today we’re releasing @tailwindcss/container-queries which is a new first-party plugin that adds container query support to the framework, using a new @ syntax to differentiate them from normal media queries:

<div class="@container">
  <div class="block @lg:flex">
    <!-- ... -->
  </div>
</div>

Out-of-the-box we include a set of container sizes that match our default max-width scale:

NameValue
xs20rem
sm24rem
md28rem
lg32rem
xl36rem
2xl42rem
3xl48rem
4xl56rem
5xl64rem
6xl72rem
7xl80rem

So there you have it — Tailwind CSS v3.2! Major improvements but just a minor version change, so no breaking changes and you should be able to update your project by just updating your dependency:

npm install -D tailwindcss@latest

For more details and always follow Official Documentation

Hashnode | Linkedin | Github