Integrating django-crispy-forms with TailwindCSS

In this post, we'll walk you through the process of integrating django-crispy-forms with TailwindCSS using the crispy-tailwind package. We'll create a small Contact Form to showcase this powerful combination.

Objectives

In this post, we'll learn how to:

  • Create a Django form class and add it to our webpage
  • Style up the form using django-crispy-forms and TailwindCSS - using the crispy-tailwind template pack
  • Create custom layouts with django-crispy-forms

Introduction

Before we dive in, let's briefly touch on what Tailwind and django-crispy-forms are:

  • TailwindCSS is a utility-first CSS framework that allows for rapid custom designs.
  • django-crispy-forms is a Django app that lets you easily build, customize and reuse forms using your favourite CSS framework.

django-crispy-forms uses Template Packs to style forms. We'll be using the crispy-tailwind template pack in this tutorial, which is a template pack designed for TailwindCSS.

We're going to start by creating a normal Django form, and will enhance this form using Tailwind as the video progresses.

Step 1: Creating a Django Form

Let's start by creating a simple Contact Form in Django. Create a file named forms.py in your Django app and add the following code:

from django import forms

class ContactForm(forms.Form):
    REASON_CHOICES = [
        ('', 'Select a reason'),
        ('general', 'General Inquiry'),
        ('support', 'Technical Support'),
        ('feedback', 'Feedback'),
        ('other', 'Other'),
    ]
    name = forms.CharField(label='Your Name', max_length=100, required=True)
    email = forms.EmailField(label='Your Email', required=True)
    reason = forms.ChoiceField(label='Reason for Contact', choices=REASON_CHOICES, required=True)
    subject = forms.CharField(label='Subject', max_length=200, required=False)
    message = forms.CharField(label='Your Message', widget=forms.Textarea(attrs={'rows': 4}), required=True)
    subscribe = forms.BooleanField(label='Subscribe to newsletter', required=False)

Next, add the form to your view:

from core.forms import ContactForm

def index(request):
    context = {'form': ContactForm()}
    return render(request, 'index.html', context)

This makes the form available for use in the index.html template. Let's add the form there.

<h1>Contact Us</h1>

<form method="POST">
    {% csrf_token %}
    {{ form }}
    <button>Submit</button>
</form>

At this point, your form will be functional but won't look great - it should appear similar to the snippet below.

Let's improve this by adding TailwindCSS and django-crispy-forms!

Step 2: Installing TailwindCSS and crispy-tailwind

For this tutorial, we'll use the TailwindCSS Play CDN (not recommended for production):

Add this to your base.html:

<script src="https://cdn.tailwindcss.com"></script>

Now, install crispy-tailwind:

pip install crispy-tailwind

After installing, we need to add both crispy-tailwind and django-crispy-forms to the Django app's INSTALLED_APPS setting. We'll also set the template pack for crispy-forms here:

INSTALLED_APPS = (
    ...
    "crispy_forms",
    "crispy_tailwind",
    ...
)

CRISPY_ALLOWED_TEMPLATE_PACKS = "tailwind"
CRISPY_TEMPLATE_PACK = "tailwind"

The template pack setting tells django-crispy-forms to use TailwindCSS for styling the form fields.

Step 3: Using the Crispy Filter

In your template, load the crispy-tailwind filters and apply the crispy filter to your form. We'll also add some TailwindCSS styles to the button in the form, as well as the container <div>

{% load tailwind_filters %}

<div class="w-full max-w-2xl mx-auto sm:px-6 lg:px-8">
    <h1 class="text-4xl font-bold mb-8">Contact Us</h1>
    <form method="POST">
        {% csrf_token %}
        {{ form|crispy }}
        <button class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800">Submit</button>
    </form>
</div>

Let's see how this looks now.

Much nicer than before!

Step 4: Advanced Customization with Crispy Forms Layouts

For more control over your form's layout, you can use Crispy Forms Layouts.

Modify your ContactForm class and add an __init__ method that creates a FormHelper object.

from crispy_forms.layout import Layout, Div, Submit
from crispy_forms.helper import FormHelper

class ContactForm(forms.Form):
    # ... (previous form fields here)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.helper = FormHelper()
        self.helper.form_class = 'border p-8'
        self.helper.layout = Layout(
            Div(
                Div('name', css_class="md:w-[50%]"),
                Div('reason', css_class="md:w-[50%]"),
                css_class="md:flex md:justify-between"
            ),
            'email',
            'subject',
            'message',
            'subscribe',
            Submit('submit', 'Submit', css_class='text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800'),
        )

Then, update your template to use the crispy template tag, rather than the template filter.

You can also remove the <form> and <button> elements from your code - crispy-forms layouts automatically generate these for you:

{% load crispy_forms_tags %}

<div class="w-full max-w-2xl mx-auto sm:px-6 lg:px-8">
    <h1 class="text-4xl font-bold mb-8">Contact Us</h1>
    {% crispy form %}
</div>

Let's take a look at this, with our new layout.

Because of our layout, with the Div elements, the first two fields of the form are inline, using flex classes.

We also have a border around the form - this was added on this line: self.helper.form_class = 'border p-8'

django-crispy-forms enables you to customize the form itself, as well as the submit button classes, from inside the Django Form class, using these FormHelper and Layout objects.

Summary

By following these steps, you've successfully integrated django-crispy-forms with TailwindCSS, creating a sleek and customizable contact form. This approach allows you to leverage the power of both frameworks, resulting in forms that are not only functional but also visually appealing.

Before we finish, remember that while this tutorial used the TailwindCSS Play CDN for simplicity, it's recommended to use a proper Tailwind setup for production environments.

If you enjoyed this post, please subscribe to our YouTube channel and follow us on Twitter to keep up with our new content!

Please also consider buying us a coffee, to encourage us to create more posts and videos!

;