Premium Tutorial. Learn Stripe Subscription with Phoenix LiveView

Read more

Tutorial

View on Github

Get started with Tailwind in Phoenix

This post was updated 16 Dec - 2020

phoenixtailwind

This tutorial is updated for Tailwind 2 and Phoenix 1.5.7

A new Phoenix app is generated with a minimal css framework and some default styles. However, my favourite CSS framework are Tailwind. So in this totorial I will go through the steps of setting in up.

Step 1 - Install Required Packages

When using Tailwind, it is also a good idea to use Purge CSS. That package is a tool to remove unused CSS and you most likely want to do that when deploying to production. Since Phoenix comes with Webpack by default, the postcss-loader is also needed.

Both postcss and autoprefixer are dev dependencies to they can be installed with the dev-flag.

Remember that the js and css code goes into the assets folder.

So run:

cd assets

yarn add -D postcss postcss-loader autoprefixer
yarn add tailwindcss

cd ..

Step 2 - Setup Tailwind and initial configuration

Now when the packages are installed, we need to configure both Webpack, PostCss and Tailwind.

// assets/webpack.config.js

use: [
  MiniCssExtractPlugin.loader,
  'css-loader',
  'sass-loader',
  'postcss-loader', // Add this
],

To configure PurgeCss, I need to add the file assets/postcss.config.js with the content:

// assets/postcss.config.js

module.exports = {
  plugins: [
    require("tailwindcss"),
    require("autoprefixer")
  ]
}

Tailwind itself is configured in its own config file.

// tailwind.config.js

module.exports = {
  purge: {
    enabled: process.env.NODE_ENV === "production",
    content: [
      "../lib/**/*.eex",
      "../lib/**/*.leex",
      "../lib/**/*_view.ex"
    ],
    options: {
      whitelist: [/phx/, /nprogress/]
    }
  }
}

Tailwind now comes with PurgeCSS built in. It means that when it builds for the production bundle, it will look in the template files and try remove the Tailwind CSS code that is not used.

Note that I specify that the purger will look on both .eex-templates, but also LiveView templates with .leex file ending. Im also specifying that this will run only in production. So, when I deploy this, I need to make sure to set enviromental variable NODE_ENV to production.

Step 3

When packages are installed and configured, the actual fun part start. Replace existing content in assets/css/app.scss and add:

@tailwind base;
@tailwind components;
@tailwind utilities;

// Other css you still want to keep

At this point, there is a good idea to start or restart the server to see if everything works as expected. If it does, we should see something like:

We know that it works because the font is the default Tailwind font on OS X.

STEP 4

What is left to do is to test this with updating the layout for the application. And I want to have a fixed navbar in the top and a sticky footer in the bottom.

So in the file lib/tutorial_web/templates/layout/app.html.eex or lib/tutorial_web/templates/layout/root.html.leex

Change the layout to:

<html lang="en" class="h-full">
  <head>
    ...
  </head>
  <body class="pt-24 flex flex-col h-full">
    <header>
      <nav class="fixed top-0 left-0 right-0 z-30 bg-white shadow">
        <div class="container mx-auto px-6 py-3 md:flex md:justify-between md:items-center">
          <div class="flex justify-between items-center">
            <div>
              <a class="inline-block" href="/">
                <img src="<%= Routes.static_path(@conn, "/images/phoenix.png") %>" class="h-8 object-contain" />
              </a>
            </div>
          </div>

          <div class="flex items-center">
            <div class="flex flex-col md:flex-row md:mx-6">
              <a href="https://hexdocs.pm/phoenix/overview.html" class="my-1 text-sm text-gray-700 font-medium hover:text-indigo-500 md:mx-4 md:my-0">Get Started</a>
              <%= if function_exported?(Routes, :live_dashboard_path, 2) do %>
                <%= link "LiveDashboard", to: Routes.live_dashboard_path(@conn, :home), class: "my-1 text-sm text-gray-700 font-medium hover:text-indigo-500 md:mx-4 md:my-0" %>
              <% end %>
            </div>
          </div>
        </div>
      </nav>
    </header>

    <%= @inner_content %>

    <footer class="bg-gray-700 mt-auto py-3">
      <div class="container pb-4 max-w-4xl mx-auto text-center text-gray-300 text-sm">
        &copy; <%= DateTime.utc_now.year %> Phoenix Tutorials
      </div>
    </footer>
  </body>
</html>

Then, since I have installed Phoenix with LiveView, I also need to update the (inner) templates:

// lib/tutorial_web/templates/layout/app.html.eex
// lib/tutorial_web/templates/layout/root.html.leex

<main role="main" class="container mx-auto max-w-3xl px-4">
  ...
</main>

RESULT AND FINAL WORDS

After almost a year with Tailwind, I am still happy. The productivity boost is of the charts. Next step will be to customize the HTML-generators so I can get the Tailwind classes out of the box.


What are you working on?

If you want, you can send me a link to your Phoenix or Phoenix LiveView project so. Lets connect on Twitter or Linkedin.

- Andreas Eriksson, web developer since 2005

Related Tutorials

Published 31 Mar - 2020

Combine Phoenix LiveView with Alpine.js

liveviewphoenixtailwindalpinejs

No matter how great Phoenix LiveView is, there is still some use case for sprinking some JS in your app to improve UX. For example, tabs, dropdowns,..

Published 11 Jul - 2020

Create a reusable modal with LiveView Component

tailwindalpinejsliveviewmodalphoenix

To reduce duplicity and complexity in your apps, Phoenix LiveView comes with the possibility to use reusable components. Each component can have its..