How to Setup Tailwind CSS with Django (Part 2)

Michael Yin

Last updated on November 10 2021

Table of Contents

Django Tailwind CSS, Alpine.js Tutorial Series:

  1. Introduction
  2. How to Setup Tailwind CSS with Django (Part 1)
  3. How to Setup Tailwind CSS with Django (Part 2)
  4. Optimize Tailwind CSS in Django
  5. Render Django Form with Tailwind CSS Style
  6. Integrate Alpine.js with Django (Part 1) (coming soon)
  7. Integrate Alpine.js with Django (Part 2) (coming soon)
  8. Build Task List with Tailwind CSS, Alpine.js and Django (coming soon)
  9. Django Form Validation in Tailwind Modal (Alpine.js) (coming soon)
  10. Django Form Validation in Tailwind Modal (Alpine.js + HTMX) (coming soon)
  11. How to deploy Django Tailwind CSS project with Docker (coming soon)

The source code is on Github/django-tailwind-alpine-htmx, demo is on Heroku

Objectives

By the end of this chapter, you should be able to:

  1. Use python-webpack-boilerplate to jump start frontend project bundled by Webpack
  2. Setup Tailwind CSS to the frontend project.

python-webpack-boilerplate

python-webpack-boilerplate can help you Jump start frontend project bundled by Webpack

Create Django project

$ mkdir django_tailwind_project && cd django_tailwind_project
$ python3 -m venv env
$ source env/bin/activate

You can also use other tools such as Poetry or Pipenv

Create requirements.txt

django==3.2
(env)$ pip install -r requirements.txt
(env)$ env/bin/django-admin.py startproject django_tailwind_app .

You will see structure like this

.
├── django_tailwind_app
├── env
├── manage.py
└── requirements.txt

Now, let's get the project running on local env.

# create db tables
(env)$ python manage.py migrate
(env)$ python manage.py runserver

Check on http://127.0.0.1:8000/, and you should be able to see the Django welcome page

Import python-webpack-boilerplate

Add python-webpack-boilerplate to the requirements.txt

django==3.2
python-webpack-boilerplate==0.0.5
(env)$ pip install -r requirements.txt

Update django_tailwind_app/settings.py to add 'webpack_boilerplate' to INSTALLED_APPS

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    'webpack_boilerplate',               # new
]

Let's run Django command to create frontend project from the python-webpack-boilerplate

$ python manage.py webpack_init
# here we use the default frontend slug
project_slug [frontend]:

Now a new frontend directory is created which contains pre-defined files for our frontend project.

├── django_tailwind_app
├── env
├── frontend                          # new
│   ├── README.md
│   ├── package-lock.json
│   ├── package.json
│   ├── postcss.config.js
│   ├── src
│   ├── vendors
│   └── webpack
├── manage.py
└── requirements.txt

Run frontend project

If you have no nodejs installed, please install it first by using below links

  1. On nodejs homepage
  2. Using nvm I recommend this way.
$ node -v
v14.18.0
$ npm -v
6.14.15
$ cd frontend

# install dependency packages
$ npm install

# launch webpack dev server
$ npm run start

If the command run without error, that means the setup works, let's terminate the npm run start by pressing Ctrl + C

Add Tailwind

By default Python Webpack Boilerplate does not contains Tailwind CSS, let's add it.

$ cd frontend

# install packages
$ npm install -D [email protected] postcss-import

You should see something like this in the frontend/package.json

"postcss-import": "^14.0.2",
"tailwindcss": "^2.2.16",

Next, let's edit postcss.config.js

// https://tailwindcss.com/docs/using-with-preprocessors

module.exports = {
  plugins: [
    require('postcss-import'),
    require('tailwindcss/nesting')(require('postcss-nesting')),
    require('tailwindcss'),
    require('postcss-preset-env')({
      features: { 'nesting-rules': false }
    }),
  ]
};

Next, generate a config file for your frontend project using the Tailwind CLI utility included when you install the tailwindcss npm package

$ cd frontend

$ npx tailwindcss init

Now tailwind.config.js is generated

module.exports = {
  purge: [],
  darkMode: false, // or 'media' or 'class'
  theme: {
    extend: {},
  },
  variants: {},
  plugins: [],
}

We will update this file after a while.

Write Tailwind CSS

Update src/application/app.js

// This is the scss entry file
import "../styles/index.scss";

window.document.addEventListener("DOMContentLoaded", function () {
  window.console.log("dom ready 1");
});

Update src/styles/index.scss

@import "tailwindcss/base";
@import "tailwindcss/components";
@import "tailwindcss/utilities";

.jumbotron {
  // should be relative path of the entry scss file
  background-image: url("../../vendors/images/sample.jpg");
  background-size: cover;
}

.btn-blue {
  @apply inline-flex items-center px-4 py-2 bg-blue-500 text-white font-semibold rounded-lg shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-opacity-75;
}

Let's test again.

$ cd frontend
$ npm run start

Now the tailwindcss can be compiled successfully, let's test in Django template.

Test in Django Template

Add code below to django_tailwind_app/settings.py

import os

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "frontend/build"),
]

WEBPACK_LOADER = {
    'MANIFEST_FILE': os.path.join(BASE_DIR, "frontend/build/manifest.json"),
}
  1. We add the above frontend/build to STATICFILES_DIRS so Django can find the static assets (img, font and others)
  2. We add MANIFEST_FILE location to the WEBPACK_LOADER so our custom loader can help us load JS and CSS.

Update django_tailwind_app/urls.py

from django.contrib import admin
from django.urls import path
from django.views.generic import TemplateView

urlpatterns = [
    path('', TemplateView.as_view(template_name="index.html")),     # new
    path('admin/', admin.site.urls),
]

Create directory for templates

$ mkdir django_tailwind_app/templates

├── django_tailwind_app
│   ├── __init__.py
│   ├── asgi.py
│   ├── settings.py
│   ├── templates               # new
│   ├── urls.py
│   └── wsgi.py

Update TEMPLATES in django_tailwind_app/settings.py, so Django can know where to find the templates

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': ['django_tailwind_app/templates'],                             # new
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

Add index.html to the above django_tailwind_app/templates

{% load webpack_loader static %}

<!DOCTYPE html>
<html>
<head>
  <title>Index</title>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  {% stylesheet_pack 'app' %}
</head>
<body>

<div class="jumbotron py-5">
  <div class="w-full max-w-7xl mx-auto px-4">
      <h1 class="text-4xl mb-4">Hello, world!</h1>
      <p class="mb-4">This is a template for a simple marketing or informational website. It includes a large callout called a
        jumbotron and three supporting pieces of content. Use it as a starting point to create something more unique.</p>

      <p><a class="btn-blue mb-4" href="#" role="button">Learn more »</a></p>

      <div class="flex justify-center">
        <img src="{% static 'vendors/images/webpack.png' %}" class="img-fluid"/>
      </div>
  </div>
</div>

{% javascript_pack 'app' %}

</body>
</html>
  1. We load webpack_loader at the top of the template, which come from python-webpack-boilerplate
  2. We can still use static to import image from the frontend project.
  3. We use stylesheet_pack and javascript_pack to load CSS and JS bundle files to Django
(env)$ python manage.py migrate
(env)$ python manage.py runserver

Now check on http://127.0.0.1:8000/ and you should be able to see a welcome page.

Workflow

  1. We use python-webpack-boilerplate to jump start frontend project.
  2. And then, we install Tailwind CSS to the frontend project to make it work.

Notes

  1. python-webpack-boilerplate is easy to extend and customize, and we can benefit from the rich Webpack ecosystem.
  2. It supports code linting on the JS and SCSS code.
  3. It supports ES6+ syntax and has JS bundle solution. For example, if we want to use axios, we can import using npm install instead of adding the CDN link to the Django template.

Django Tailwind CSS, Alpine.js Tutorial Series:

  1. Introduction
  2. How to Setup Tailwind CSS with Django (Part 1)
  3. How to Setup Tailwind CSS with Django (Part 2)
  4. Optimize Tailwind CSS in Django
  5. Render Django Form with Tailwind CSS Style
  6. Integrate Alpine.js with Django (Part 1) (coming soon)
  7. Integrate Alpine.js with Django (Part 2) (coming soon)
  8. Build Task List with Tailwind CSS, Alpine.js and Django (coming soon)
  9. Django Form Validation in Tailwind Modal (Alpine.js) (coming soon)
  10. Django Form Validation in Tailwind Modal (Alpine.js + HTMX) (coming soon)
  11. How to deploy Django Tailwind CSS project with Docker (coming soon)

The source code is on Github/django-tailwind-alpine-htmx, demo is on Heroku


Michael Yin

Michael is a Full Stack Developer from China who loves writing code, tutorials about Django, and modern frontend tech.

He has published some ebooks on leanpub and tech course on testdriven.io.

He is also the founder of the AccordBox which provides the web development services.


Table of Contents

Frontend Guide For Python Dev

This FREE guide help Python developers to learn the Modern frontend tech

Learn More

Build Jamstack web app with Next.js and Wagtail CMS.

Read More

Subscribe

Get notified about new great Web Development Tutorial