In the 15 or so years since I started making WordPress websites, nothing has had more of an impact on my productivity — and my ability to enjoy front-end development — than adding Tailwind CSS to my workflow (and it isn’t close).
When I began working with Tailwind, there was an up-to-date, first-party repository on GitHub describing how to use Tailwind with WordPress. That repository hasn’t been updated since 2019. But that lack of updates isn’t a statement on Tailwind’s utility to WordPress developers. By allowing Tailwind to do what Tailwind does best while letting WordPress still be WordPress, it’s possible to take advantage of the best parts of both platforms and build modern websites in less time.
The minimal setup example in this article aims to provide an update to that original setup repository, revised to work with the latest versions of both Tailwind and WordPress. This approach can be extended to work with all kinds of WordPress themes, from a forked default theme to something totally custom.
Why WordPress developers should care about Tailwind
Before we talk about setup, it’s worth stepping back and discussing how Tailwind works and what that means in a WordPress context.
Tailwind allows you to style HTML elements using pre-existing utility classes, removing the need for you to write most or all of your site’s CSS yourself. (Think classes like hidden
for display: hidden
or uppercase
for text-transform: uppercase
.) If you’ve used frameworks like Bootstrap and Foundation in the past, the biggest difference you’ll find with Tailwind CSS is its blank-slate approach to design combined with the lightness of being CSS-only, with just a CSS reset included by default. These properties allow for highly optimized sites without pushing developers towards an aesthetic built into the framework itself.
Also unlike many other CSS frameworks, it’s infeasible to load a “standard” build of Tailwind CSS from an existing CDN. With all of its utility classes included, the generated CSS file would simply be too large. Tailwind offers a “Play CDN,” but it’s not meant for production, as it significantly reduces Tailwind’s performance benefits. (It does come in handy, though, if you want to do some rapid prototyping or otherwise experiment with Tailwind without actually installing it or setting up a build process.)
This need to use Tailwind’s build process to create a subset of the framework’s utility classes specific to your project makes it important to understand how Tailwind decides which utility classes to include, and how this process affects the use of utility classes in WordPress’s editor.
And, finally, Tailwind’s aggressive Preflight (its version of a CSS reset) means some parts of WordPress are not well-suited to the framework with its default settings.
Let’s begin by looking at where Tailwind works well with WordPress.
Where Tailwind and WordPress work well together
In order for Tailwind to work well without significant customization, it needs to act as the primary CSS for a given page; this eliminates a number of use cases within WordPress.
If you’re building a WordPress plugin and you need to include front-end CSS, for example, Tailwind’s Preflight would be in direct conflict with the active theme. Similarly, if you need to style the WordPress administration area — outside of the editor — the administration area’s own styles may be overridden.
There are ways around both of these issues: You can disable Preflight and add a prefix to all of your utility classes, or you could use PostCSS to add a namespace to all of your selectors. Either way, your configuration and workflow are going to get more complicated.
But if you’re building a theme, Tailwind is an excellent fit right out of the box. I’ve had success creating custom themes using both the classic editor and the block editor, and I’m optimistic that as full-site editing matures, there will be a number of full-site editing features that work well alongside Tailwind.
In her blog post “Gutenberg Full Site Editing does not have to be full,” Tammie Lister describes full-site editing as a set of separate features that can be adopted in part or in full. It’s unlikely full-site editing’s Global Styles functionality will ever work with Tailwind, but many other features probably will.
So: You’re building a theme, Tailwind is installed and configured, and you’re adding utility classes with a smile on your face. But will those utility classes work in the WordPress editor?
With planning, yes! Utility classes will be available to use in the editor so long as you decide which ones you’d like to use in advance. You’re unable to open up the editor and use any and all Tailwind utility classes; baked into Tailwind’s emphasis on performance is the limitation of only including the utility classes your theme uses, so you need to let Tailwind know in advance which ones are required in the editor despite them being absent elsewhere in your code.
There are a number of ways to do this: You can create a safelist within your Tailwind configuration file; you can include comments containing lists of classes alongside the code for custom blocks you’ll want to style in the block editor; you could even just create a file listing all of your editor-specific classes and tell Tailwind to include it as one of the source files it monitors for class names.
The need to commit to editor classes in advance has never held me back in my work, but this remains the aspect of the relationship between Tailwind and WordPress I get asked about the most.
A minimal WordPress theme with a minimal Tailwind CSS integration
Let’s start with the most basic WordPress theme possible. There are only two required files:
style.css
index.php
We’ll generate style.css
using Tailwind. For index.php
, let’s start with something simple:
<!doctype html>
<html lang="en">
<head>
<?php wp_head(); ?>
<link rel="stylesheet" href="<?php echo get_stylesheet_uri(); ?>" type="text/css" media="all" />
</head>
<body>
<?php
if ( have_posts() ) {
while ( have_posts() ) {
the_post();
the_title( '<h1 class="entry-title">', '</h1>' );
?>
<div class="entry-content">
<?php the_content(); ?>
</div>
<?php
}
}
?>
</body>
</html>
There are a lot of things a WordPress theme should do that the above code doesn’t — things like pagination, post thumbnails, enqueuing stylesheets instead of using link
elements, and so on — but this will be enough to display a post and test that Tailwind is working as it should.
On the Tailwind side, we need three files:
package.json
tailwind.config.js
- An input file for Tailwind
Before we go any further, you’re going to need npm. If you’re uncomfortable working with it, we have a beginner’s guide to npm that is a good place to start!
Since there is no package.json
file yet, we’ll create an empty JSON file in the same folder with index.php
by running this command in our terminal of choice:
echo {} > ./package.json
With this file in place, we can install Tailwind:
npm install tailwindcss --save-dev
And generate our Tailwind configuration file:
npx tailwindcss init
In our tailwind.config.js
file, all we need to do is tell Tailwind to search for utility classes in our PHP files:
module.exports = {
content: ["./**/*.php"],
theme: {
extend: {},
},
plugins: [],
}
If our theme used Composer, we’d want to ignore the vendor
directory by adding something like "!**/vendor/**"
to the content
array. But if all of your PHP files are part of your theme, the above will work!
We can name our input file anything we want. Let’s create a file called tailwind.css
and add this to it:
/*!
Theme Name: WordPress + Tailwind
*/
@tailwind base;
@tailwind components;
@tailwind utilities;
The top comment is required by WordPress to recognize the theme; the three @tailwind
directives add each of Tailwind’s layers.
And that’s it! We can now run the following command:
npx tailwindcss -i ./tailwind.css -o ./style.css --watch
This tells the Tailwind CLI to generate our style.css
file using tailwind.css
as the input file. The --watch
flag will continuously rebuild the style.css
file as utility classes are added or removed from any PHP file in our project repository.
That’s as simple as a Tailwind-powered WordPress theme could conceivably be, but it’s unlikely to be something you’d ever want to deploy to production. So, let’s talk about some pathways to a production-ready theme.
Adding TailwindCSS to an existing theme
There are two reasons why you might want to add Tailwind CSS to an existing theme that already has its own vanilla CSS:
- To experiment with adding Tailwind components to an already styled theme
- To transition a theme from vanilla CSS to Tailwind
We’ll demonstrate this by installing Tailwind inside Twenty Twenty-One, the WordPress default theme. (Why not Twenty Twenty-Two? The most recent WordPress default theme is meant to showcase full-site editing and isn’t a good fit for a Tailwind integration.)
To start, you should download and install the theme in your development environment if it isn’t installed there. We only need to follow a handful of steps after that:
- Navigate to the theme folder in your terminal.
- Because Twenty Twenty-One already has its own
package.json
file, install Tailwind without creating a new one:
npm install tailwindcss --save-dev
- Add your
tailwind.config.json
file:
npx tailwindcss init
- Update your
tailwind.config.json
file to look the same as the one in the previous section. - Copy Twenty Twenty-One’s existing
style.css
file totailwind.css
.
Now we need to add our three @tailwind
directives to the tailwind.css
file. I suggest structuring your tailwind.css file as follows:
/* The WordPress theme file header goes here. */
@tailwind base;
/* All of the existing CSS goes here. */
@tailwind components;
@tailwind utilities;
Putting the base
layer immediately after the theme header ensures that WordPress continues to detect your theme while also ensuring the Tailwind CSS reset comes as early in the file as possible.
All of the existing CSS follows the base
layer, ensuring that these styles take precedence over the reset.
And finally, the components
and utilities
layers follow so they can take precedence over any CSS declarations with the same specificity.
And now, as with our minimal theme, we’ll run the following command:
npx tailwindcss -i ./tailwind.css -o ./style.css --watch
With your new style.css
file now being generated each time you change a PHP file, you should check your revised theme for minor rendering differences from the original. These are caused by Tailwind’s CSS reset, which resets things a bit further than some themes might expect. In the case of Twenty Twenty-One, the only fix I made was to add text-decoration-line: underline
to the a
element.
With that rendering issue resolved, let’s add the Header Banner Component from Tailwind UI, Tailwind’s first-party component library. Copy the code from the Tailwind UI site and paste it immediately following the “Skip to content” link in header.php
:

Pretty good! Because we’re now going to want to use utility classes to override some of the existing higher-specificity classes built into the theme, we’re going to add a single line to the tailwind.config.js
file:
module.exports = {
important: true,
content: ["./**/*.php"],
theme: {
extend: {},
},
plugins: [],
}
This marks all Tailwind CSS utilities as !important
so they can override existing classes with a higher specificity. (I’ve never set important
to true
in production, but I almost certainly would if I were in the process of converting a site from vanilla CSS to Tailwind.)
With a quick no-underline
class added to the “Learn more” link and bg-transparent
and border-0
added to the dismiss button, we’re all set:

It looks a bit jarring to see Tailwind UI’s components merged into a WordPress default theme, but it’s a great demonstration of Tailwind components and their inherent portability.
Starting from scratch
If you’re creating a new theme with Tailwind, your process will look a lot like the minimal example above. Instead of running the Tailwind CLI directly from the command line, you’ll probably want to create separate npm scripts for development and production builds, and to watch for changes. You may also want to create a separate build specifically for the WordPress editor.
If you’re looking for a starting point beyond the minimal example above — but not so far beyond that it comes with opinionated styles of its own — I’ve created a Tailwind-optimized WordPress theme generator inspired by Underscores (_s), once the canonical WordPress starter theme. Called _tw, this is the quick-start I wish I had when I first combined Tailwind with WordPress. It remains the first step in all of my client projects.
If you’re willing to go further from the structure of a typical WordPress theme and add Laravel Blade templates to your toolkit, Sage is a great choice, and they have a setup guide specific to Tailwind to get you started.
However you choose to begin, I encourage you to take some time to acclimate yourself to Tailwind CSS and to styling HTML documents using utility classes: It may feel unusual at first, but you’ll soon find yourself taking on more client work than before because you’re building sites faster than you used to — and hopefully, like me, having more fun doing it.
Thank you, this article is useful for me. When starting a new site, I’ll probably use Tailpress, but this article would be helpful in other situations like adding on to an existing theme.
I’m happy to hear you found it useful!
My goal was to share a minimal setup both to show how the most basic possible integration would work, and to show what is needed to add Tailwind to an existing WordPress theme. I completely agree that it makes sense to begin with an existing starter theme when creating a new site! I built a Tailwind-optimized WordPress theme generator for that purpose—I’d love to hear what you think if you have a chance to check it out!
I’ve never tried Tailwind on WordPress because of the menus and submenus.
How do you style those components whose html that usually are generated by a WordPress function?
I will also look for some info about styling blocks with tailwind, but I think the easiest way is to follow the typical class and @apply approach for blocks and then, using tailwind with just css classes for the rest.
When I first heard about Tailwind, I had very similar concerns. Almost all of the time (and my experience with menus is that this is certainly the case), you can use
@apply
to style components via the classes in WordPress’s generated HTML.Occasionally you’ll find there aren’t the classes or wrapper elements you need in the generated HTML, and at that point you may need to modify the generated HTML via filters. I’ve rarely needed to do this, and it’s been more common for me with plugins than with WordPress core.
You’re absolutely right regarding blocks: I’ve generally been styling them using
@apply
targeting the existing classes.Hey Greg!
Fabulous post from you, thank you fordoing this.
I want to dive in with tailwind, theme and blocks. I had work with Kadence as first well organized theme&block solution where global parameters works as expected.
I can feel importance of tailwind nowadays. Is it possible to get more tutorials from you of your work flow.
More specifically
– I’m interested in answer to the question how designers work flow (ex figma) are influenced by tailwind on the back.
– I’m interested to see how you create page from scratch (or figma) with tailwind.
Kindly let me know youtube or something to find answers please.
Best, Alex
Hi Alex!
Thanks very much for your comment—I’m very happy to hear you enjoyed the article!
I’m working on more screencasts for _tw, but I don’t have anything imminent. (There’s a GitHub issue that I plan to close when I get something online, so you could watch that if you wanted.)
Lately most of my work has started in Figma. I don’t know that I have a single recipe for my approach, as the designs I receive can vary so much. I tend to begin by deciding which parts will be user-editable in the block editor versus what will be structured data (using something like Advanced Custom Fields). I tend not to trust that the deliverable will have a totally consistent set of colours and fonts sizes/families, so I do my own audit rather than rely on the palettes included with the file. (Your experience may vary on how necessary this is.)
You’d probably get something out of a screencast like this one from Tailwind Labs:
Translating a Custom Design System to Tailwind CSS
(They have a lot of great first-party screencasts, though to my knowledge nothing specific to WordPress.)
Hope that helps!
Hey Greg
Thanks for the article, some great content in here and I think you did a good job of explaining some of the barriers to getting a fully integrated experience with Tailwind CSS and WordPress.
This is something that, as a freelance developer, I’ve been running into also. I want to be able to use Tailwind to build my themes, but I don’t want to get stuck with any subset of classes to use.
It’s one of the reasons I started building Gust and I’d love for you take a look and see what you think. It tries to solve most of the issues mentioned above, allowing developers to build themes with Tailwind but also allowing you to use a drag / drop editor to build individual pages with Tailwind. It’s kind of similar to Tailpress and your Tailwind template mentioned in the above comments, but with some deeper integration.
At the moment Gust is a premium theme but if you ( and any other readers ) want to try out a demo you can check out the free version here which gives the same editing experience without a few of the extra features. Hope you enjoy it!
Cheers!
Matt
Hi Matt,
Thanks very much for your comment—I’ve looked at Gust’s website in the past, so I’m definitely familiar with your project!
On using a subset of classes: My first priority is making sure my clients don’t interact with Tailwind classes in any way; if I’m working on new page layouts or designs, I’ll be doing that in a development environment, and I can create appropriate components there. My ideal is to make all of this transparent to clients, ensuring they never need to add or remove classes of any kind when editing pages, whether this means using block editor styles or custom page templates for pages with too much structured data to be a good fit for the block editor. (And I acknowledge that where that line falls varies a lot from developer to developer.)
Thanks for posting the free version of your theme! I’ll take a look for sure.
Yeah, you’re totally right, we don’t want clients having to add classes themselves. It all depends on how tech savvy your clients are, but I found that often times I would set up the templates etc but the client still wanted to be able to build landing pages themselves or update xyz page without having that either hard coded or coming back to me to build it. This requirement is what inspired having pre-built components so that the client can just drag and drop a hero section or something, without having to work with class names, code etc, and with the way we’ve set up Gust, the CSS for all these components won’t be included unless the components are included on a page.
I found it struck a nice balance between allowing the customer to edit the site without technical knowledge and not overloading the site with unused CSS to accommodate it.
Anyway, as you said, the lines here vary from developer to developer and your mileage may vary. I’ve been finding it helpful and hopefully someone else here will too :)
Thanks again!
Hey Matt,
That totally makes sense! Have you used block editor patterns at all in your client work? I don’t know that WordPress core is 100% of the way there yet in having this be seamless for client work, but it’s getting very, very close.
Thanks again!
Great article! I’ve been trying to work in Tailwind to my regular WordPress dev flow for quite awhile. This has been helpful for custom theme dev.
However, with Full Site Editing and block themes, I needed a bit of an easier solution that didn’t require compiling. So I made this Tailwind for WordPress plugin. Just activate and you can start using TW on both the front and backend without any performance hit, since I cache all the generated CSS.
If you try it out and find it useful too, feel free to add this to your article!
I ran into your plugin the other day! It looks to me like a separate CSS file was generated for each URL on the site—is this the case? Is there any mechanism for rebuilding the cache if a site-wide element like part of the header or footer changes and requires new classes?
Not currently but that’s a great idea! I’ll try and release that soon:
https://github.com/wpmotto/tailpress/issues/4
I’m also looking into consolidating some of the overlapping styles across pages so there’s not too much duplication. I’ll enqueue these as linked stylesheets so the browser can make use of caching more global styles coming from TW.
I’ll definitely keep an eye on it! I saw the GitHub issue on user-generated content, and I’m interested to see how you handle that side of things as well. A malicious user pasting in hundreds or thousands of Tailwind classes to create a very large CSS file is an attack vector I never would have considered, as I’ve never run Tailwind on server-side pages.
Totally, I hadn’t considered that either, but I have an idea of how I might be able to get around that so look out for that fix in the coming weeks.
thank u so much
is there any way to not ctrl+f5 after style update?
You’re very welcome! Depending on your development environment, you should be able to install Browsersync to save you from manually refreshing after each change.