← Home

Since Django 4 form rendering with Tailwind can be used to render beautiful forms without using Node or any other packages like django-crispy-forms.

All you need is the Tailwind CLI binary and django-widget-tweaks.

Tailwind without Node

The pytailwindcss package bundles the Tailwind CLI as a self-contained binary: not need to install Node!

The downside is, that it’s not possible to use any Tailwind plugins except for the built-in ones like @tailwindcss/forms.

pip install pytailwindcss

or put

pytailwindcss==0.1.4

into your requirements.txt (you should do that anyway).

Create an entry point for Tailwind in static/css/project.css:

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

Create a Tailwind configuration file in your project root to tell Tailwind where your templates are:

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ["./<project>/**/*.{html,js}"],
  theme: {
    extend: {},
  },
  plugins: [require("@tailwindcss/forms")],
};

Whenever you run the local development server, also run the Tailwind compiler:

tailwindcss --watch -i <project>/static/css/project.css -o <project>/static/css/dist/styles.css

Include the compiled CSS as static file in your base template templates/base.html:

<link href="{% static 'css/dist/styles.css' %}" rel="stylesheet">

Custom Django 4 form rendering

In order to customize the form rendering, define and configure a custom form renderer in your settings.py:

from django.forms.renderers import TemplatesSetting

class FormRenderer(TemplatesSetting):
    form_template_name = "form_snippet.html"


FORM_RENDERER = "config.settings.base.FormRenderer"

Use django-widget-tweaks to add custom Tailwind classes to the input elements. Implement your own form rendering template form_snipper.html.

The following snippet covers the most basic input elements, feel free to implement your own.

{% load widget_tweaks %}
<div class="grid grid-cols-1 gap-6">
  {% for field in form %}
  <label class="block">
    <span class="text-gray-700"
      >{{ field.label }}</span
    >
    <!-- Checkbox -->
    {% if field|field_type == 'booleanfield' %} {{
    field|add_class:"rounded border-gray-300
    text-indigo-600 shadow-sm
    focus:border-indigo-300 focus:ring
    focus:ring-offset-0 focus:ring-indigo-200
    focus:ring-opacity-50" }}
    <!-- Date -->
    {% elif field|field_type == 'datefield' %} {{
    field|add_class:"mt-1 block w-full rounded-md
    border-gray-300 shadow-sm
    focus:border-indigo-300 focus:ring
    focus:ring-indigo-200 focus:ring-opacity-50"
    }}
    <!-- Email -->
    {% elif field|field_type == 'emailfield' %} {{
    field|add_class:"mt-1 block w-full rounded-md
    border-gray-300 shadow-sm
    focus:border-indigo-300 focus:ring
    focus:ring-indigo-200
    focus:ring-opacity-50"|attr:"placeholder:" }}
    <!-- Password -->
    {% elif field|field_type == 'passwordfield' %}
    {{ field|add_class:"mt-1 block w-full
    rounded-md border-gray-300 shadow-sm
    focus:border-indigo-300 focus:ring
    focus:ring-indigo-200
    focus:ring-opacity-50"|attr:"placeholder:" }}
    {% else %}
    <!-- Fallback -->
    {{ field }} {% endif %}
  </label>
  {% endfor %}
</div>

Tailwind is great with components. Django templates are not great with components.

It’s a good idea to define custom classes for highly re-usable elements like buttons and links. Define them in static/css/project.css.

Note that if you are using Tailwind with a framework like React, you should not define your custom CSS classes but instead heavily break down your UI into components.

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

@layer components {
  .btn-link {
    @apply font-medium text-indigo-600 hover:text-indigo-500;
  }

  .btn-primary {
    @apply items-center justify-center 
    rounded-md border border-transparent bg-indigo-600 
    px-4 py-2 text-base font-medium text-white 
    shadow-sm hover:bg-indigo-700;
  }
}

Now all your forms will automatically look nice!

All your forms look good

<form
  class="login"
  method="POST"
  action="{% url 'account_login' %}"
>
  {% csrf_token %} {{ form }} {% if
  redirect_field_value %}
  <input
    type="hidden"
    name="{{ redirect_field_name }}"
    value="{{ redirect_field_value }}"
  />
  {% endif %}
  <a
    class="btn-link"
    href="{% url 'account_reset_password' %}"
    >{% trans "Forgot Password?" %}</a
  >
  <button class="btn-primary" type="submit">
    {% trans "Sign In" %}
  </button>
</form>

image Don’t forget to run the Tailwind CLI with the --minify argument in your deployment step in order to optimize the CSS:

tailwindcss \
  --minify \
  -i mentionedd/static/css/project.css \
  -o mentionedd/static/css/dist/styles.css
← Home

Erben Systems GmbH

Watterstrasse 81, c/o Sarbach Treuhand AG, 8105 Regensdorf, Switzerland

CHE-174.268.027 MwSt