April 24, 2020
•Last updated November 5, 2023
How to install Tailwind CSS using Ruby on Rails
In this guide, you'll learn how to install Tailwind CSS using Ruby on Rails
Looking for support for Tailwind CSS 2?
Head here for an updated guide
It occurred to me recently that I never actually recorded a screencast about installing Tailwind CSS within the Ruby on Rails framework.
For most screencasts, I tend to lean for my kickoff_tailwind application template as a quick way to get a new app up and running. Inside the template, I have the process of installing Tailwind CSS automated minus a few PostCSS configuration settings.
While it's relatively straight forward, there are some quirks to the process. I hope you find this guide useful. The written form below will be a bit brief while the video goes into more depth about the details.
I'd recommend referring the Tailwind documentation if you get hung up.
Create a new rails app
This is quite straight forward. At the time of recording/writing, I'm using Rails 6.0.2 and Ruby 2.6.6.
$ rails new tailwind_demo
Rails 6 gives us webpack configurations by default. We also get support for PostCSS which is a requirement to get Tailwind installed.
Installing Tailwind CSS
Within your new rails app run the following:
$ yarn add tailwindcss
Getting our app ready for Tailwind
There are a few tasks to do once the node package is installed in order for Rails to play nicely with the framework. I'll go into more details but here's a quick outline:
- Set up our
postcss.config.js
file to require the new node module and provide a relative path to a file calledtailwind.config.js
- Create a
tailwind.config.js
file. - Create the main CSS file where we import Tailwind CSS specific modules.
- Add our stylesheet pack tag to the main application layout view (or your view of choice).
- Consider using PurgeCSS to reduce the file size of our final CSS output.
PostCSS configuration.
At the root of your Rails project, you should find a postcss.config.js
file. Inside this file will already be some code. We're going to append more to the file. I prefer the following format:
// postcss.config.js
let environment = {
plugins: [
require('tailwindcss')('./app/javascript/stylesheets/tailwind.config.js'),
require('postcss-import'),
require('postcss-flexbugs-fixes'),
require('postcss-preset-env')({
autoprefixer: {
flexbox: 'no-2009'
},
stage: 3
})
]
};
module.exports = environment;
I've added a new require('tailwindcss)
line to tell our PostCSS configuration to use Tailwind CSS. Tailwind requires a configuration file that we pass in parenthesis following the require statement. You can put your configuration file anywhere in your project but I tend to group things inside app/stylesheets
as it's all related to Tailwind. The Tailwind CSS documentation states to add autoprefixer
as well. Luckily enough we already have that installed so we save a step.
Create a tailwind.config.js
file.
The heart of Tailwind CSS is the config file. Here you define your own theme options and plugins. Tailwind takes an unopinionated approach so the possibilities here are endless. I'm going to make use of the default theme that ships with Tailwind CSS for brevity's sake. We can generate this all from the command line:
$ npx tailwindcss init --full
This command should create a tailwind.config.js
file at the root of your project with the default theme configuration inside. As I stated before, I prefer to have my tailwind.config.js
file live inside app/stylesheets
. You'll need to create this folder as it won't exist initially.
Add Tailwind to your CSS
Inside app/stylesheets
create a new file called application.scss
(or whatever you prefer here). This file will be what we import inside our default app/javascript/packs/application.js
file. Since this is all generated with JavaScript, this is all totally possible.
/* app/javascript/stylesheets/application.scss */
@import "tailwindcss/base";
@import "tailwindcss/components";
// You can add your own custom components/styles here
@import "tailwindcss/utilities";
Next, we need to import this file into our app/javascript/packs/application.js
file. That's as simple as:
// app/javascript/packs/application.js
require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")
// Tailwind CSS
import "stylesheets/application" // ADD THIS LINE
Update layout template
We need a way for our HTML to absorb our work this far. With modern versions of Rails our work is nearly complete thanks to the addition of the javascript_pack_tag
inside our app/views/layouts/application.html.erb
file. We still need to add a stylesheet_pack_tag
to that same template to get things to work.
Note the pre-existing stylesheet_link_tag
. Legacy versions of Rails tended to use what is called the Asset Pipeline. This is still in use today but the idea is everything within your app/assets/stylesheets
directly would get compiled down into one file for use here. The way it worked is an inspiration for a lot of build processes you find today. I definitely recommend studying up on it if you're interested.
Today's conventions assume you'll only use the Asset Pipeline for CSS and images and leave Webpack for your javascript. So everything inside app/javascript
is all Webpack as a result.
<!-- app/views/layouts/application.html.erb -->
<!DOCTYPE html>
<html>
<head>
<title>TailwindDemo</title>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= stylesheet_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>
<body>
<%= yield %>
</body>
</html>
Testing your work
Testing your work is pretty simple at this point. We need a way to see a basic template that isn't the default welcome screen Rails ships with.
$ rails generate controller static index
The command above will generate a static controller with an index action. The app/views/
folder should receive a new folder called static
with a file called index.html.erb
inside.
Update your routes
To test things out easily we can make our new static#index
action our root path in our config/routes.rb
file.
# config/routes.rb
Rails.application.routes.draw do
root to: 'static#index'
end
Booting your server should get you to a functioning app with Tailwind CSS resetting all the text you see on the screen.
$ rails server
From here you can play around with classes on the body tag for example.
<!-- app/views/layouts/application.html.erb -->
<!DOCTYPE html>
<html>
<head>
<title>TailwindDemo</title>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= stylesheet_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
</head>
<body class="bg-black text-white font-sans">
<%= yield %>
</body>
</html>
Tips for reducing file size
When shipping Tailwind CSS to a production environment the file sizes can get massive thanks to all the classes that get generated. To reduce file sizes you can either clean up your configuration file a bit and/or use a tool like Purge-CSS.
This tool will find and compare any classes not in use in your app and remove them during compilation. It's super convenient and powerful but comes with a few quirks.
Installing is simple, just like we did Tailwind CSS
$ yarn add @fullhuman/postcss-purgecss
You'll want to save this as a regular dependency and not a dev dependency.
Setting it up gets a little more challenging. We need to modify our postcss.config.js
file once again to account for the new module.
// postcss.config.js
let environment = {
plugins: [
require('tailwindcss')('./app/javascript/stylesheets/tailwind.config.js'),
require('postcss-import'),
require('postcss-flexbugs-fixes'),
require('postcss-preset-env')({
autoprefixer: {
flexbox: 'no-2009'
},
stage: 3
})
]
};
// Add everything below!
if (process.env.RAILS_ENV === 'production') {
environment.plugins.push(
require('@fullhuman/postcss-purgecss')({
content: [
'./app/**/.html.erb',
'./app/helpers/**/*.rb',
'./app/javascript/**/*.js',
'./app/javascript/**/*.vue',
'./app/javascript/**/*.jsx',
],
defaultExtractor: (content) => content.match(/[A-Za-z0-9-_:/]+/g) || []
})
)
}
module.exports = environment;
The biggest change to understand here is that we only want to run purgecss in our production environment. In our development environment it's not a big default to have larger file sizes.
We take our environment
variable and push the new module onto the plugins
array. From there we pass in an array called content
which accepts relative paths that purgecss should look for when doing its work. Finally using the defualtExtractor
method we can pass a RegEx pattern that instructs purgecss what to look for.
Gotchas
I've run into issues before where any custom CSS I add within app/javascript/stylesheets/application.scss
gets removed. To cure this issue I found a way to whitelist that CSS using some handy commenting patterns from purgecss.
That might look like the following:
@import "tailwindcss/base";
@import "tailwindcss/components";
/*! purgecss start ignore */
@import "components/buttons";
body {
@apply bg-blue-500 text-white;
}
/*! purgecss end ignore */
@import "tailwindcss/utilities";
Be sure to include the !
marks otherwise they will be stripped out. This code assumes you made a components
folder inside app/javascript/stylesheets
and a file called _buttons.scss
.
Shameless plug time
I have a new course called Hello Rails. Hello Rails is a modern course designed to help you start using and understanding Ruby on Rails fast. If you're a novice when it comes to Ruby or Ruby on Rails I invite you to check out the site. The course will be much like these builds but a super more in-depth version with more realistic goals and deliverables. Download your copy today!!
Follow @hello_rails and myself @justalever on Twitter.
Categories
Collection
Part of the Ruby on Rails collection
Products and courses
-
Hello Hotwire
A course on Hotwire + Ruby on Rails.
-
Hello Rails
A course for newcomers to Ruby on Rails.
-
Rails UI
UI templates and components for Rails.