PhxTailwindGenerators
A scaffold generator for new resources which uses Tailwind CSS and not the default Milligram.
If you already have a Tailwind system up and running within your Phoenix application than you just have to add {:phx_tailwind_generators, "~> 0.1.6"}
to your mix.exs
and run a mix deps.get
to get access to the mix phx.gen.tailwind Blog Post posts title body:text
generator.
In case you don't have a Phoenix with Tailwind setup yet you have two choices:
- https://fullstackphoenix.com/boilerplates will do the heavy lifting for you.
- Read the following small Howto.
Setup Phoenix with Tailwind
A step by step howto to setup a Phoenix system with Tailwind CSS. When useful I use the output of diff to describe where to include/change code (the first number is the line number).
I promise to not use "this is easy". Nothing is easy if you don't know how to do it.
A green field
We start with a fresh Phoenix application named example_shop
:
$ mix phx.new example_shop
$ cd example_shop
$ mix ecto.create
Add PostCSS
PostCSS is a tool for transforming CSS with JavaScript.
$ cd assets
$ npm install tailwindcss postcss autoprefixer [email protected] --save-dev
$ cd ..
Create the following file with this content:
assets/postcss.config.js
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
}
}
Open the file assets/webpack.config.js in the
editor of your choice. Search for sass-loader
and add 'postcss-loader',
before it.
The diff:
41a42
> 'postcss-loader',
Purge unused styles in production
This makes for a minimal CSS file in your production environment. This results in a better WebPerformance.
$ cd assets
$ npx tailwind init
$ cd ..
Open the file assets/tailwind.config.js with an editor and change it according this diff:
2c2,8
< purge: [],
---
> purge: [
> "../**/*.html.eex",
> "../**/*.html.leex",
> "../**/views/**/*.ex",
> "../**/live/**/*.ex",
> "./js/**/*.js",
> ],
Do this change in assets/package.json
6c6
< "deploy": "webpack --mode production",
---
> "deploy": "NODE_ENV=production webpack --mode production",
Replace assets/css/app.scss with this code:
/* This file is for your main application css. */
@tailwind base;
@tailwind components;
@tailwind utilities;
Remove the not needed default Phoenix CSS:
$ rm assets/css/phoenix.css
Now you have a running Tailwind CSS system within your Phoenix application!
The test: Fire up your Phoenix application with mix phx.server
and open http://localhost:4000 with your browser. Open lib/example_shop_web/templates/page/index.html.eex
in your editor and search for a <h1>
or <p>
element. Add class="text-red-500"
to it and watch it turn red in your browser.
Of course you have to customize lib/example_shop_web/templates/layout/app.html.eex
to get a nice layout. You find some good examples at https://tailwindui.com
Add CSS for the forms
We are not 100% there yet because we need some extra CSS for forms. But that is done in two steps:
$ cd assets
$ npm install @tailwindcss/forms
$ cd ..
Change assets/tailwind.config.js according to this diff.
16,17c16,19
< plugins: [],
< }
---
> plugins: [
> require('@tailwindcss/forms'),
> ],
> };
Now you can install the generator.
Installation of the generator
If available in Hex, the package can be installed
by adding phx_tailwind_generators
to your list of dependencies in mix.exs
:
def deps do
[
{:phx_tailwind_generators, "~> 0.1.6"}
]
end
Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/phx_tailwind_generators.
Use of the generator
The generator works like the default scaffold generator. Only the name is different:
mix phx.gen.tailwind Blog Post posts title body:text
This will create templates which use Tailwind CSS. Have fun with it.
Please do submit bugs or better create pull requests!
Bonus: Install Alpine.js
Since you are now using Phoenix with Tailwind the chances are high that you want to use Alpine.js too. Follow me.
$ cd assets
$ npm install alpinejs
$ cd ..
Open assets/js/app.js in your editor and add these lines to the bottom:
let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
// Alpinejs
import Alpine from "alpinejs"
let liveSocket = new LiveSocket("/live", Socket, {
params: { _csrf_token: csrfToken },
dom: {
onBeforeElUpdated(from, to) {
if (from.__x) { Alpine.clone(from.__x, to) }
}
}
})
You can test your new setup with this example code. Just place it in lib/example_shop_web/templates/page/index.html.eex
and click on the blue button.
<div x-data="{ open: false }">
<button @click="open = true" class="inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md shadow-sm text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">Open Dropdown</button>
<ul
x-show="open"
@click.away="open = false"
>
Dropdown Body
</ul>
</div>
Acknowledgments
Very little in this repository was created by me. Most of this is copy and pasted from other resources. And the whole mix package wouldn't exist without the help of James Edward Gray II who walked me through the steps of creating it.
Resources I used: