Customizing HTML for a Model Form

Hi, I want all my Django applications going forward to be styled using only Tailwind. The main difficulty is with Django forms. I’ve been trying the approach of adding Tailwind classes to Model Form widgets using Django 4.2.1 with django-tailwind installed as the app: ‘theme’. I’ve been looking at this tutorial in the ‘Customize Built-in Widgets’ section. The idea is to customize each widget type with Tailwind classes in one place so it has the same style in all forms where it’s used.

Here’s what I’ve done so far:

  • copied the widget html flies from django/forms/templates/django/forms/widgets/ to myproject/themes/django/forms/widgets/
  • In settings.py,
    • set FORM_RENDERER = ‘django.forms.renderers.TemplatesSetting’
    • added django.forms to INSTALLED_APPS
  • edited myproject/themes/django/forms/widgets/input.html to include Tailwind classes:
<input 
  class="mt-1 block w-full rounded-md border-indigo-300 shadow-sm
       focus:border-indigo-301 focus:ring focus:ring-indigo-200
       focus:ring-opacity-50"
  type="{{ widget.type }}"
  name="{{ widget.name }}"{% if widget.value != None %}
  value="{{ widget.value|stringformat:'s' }}"
{% endif %}{% include "django/forms/widgets/attrs.html" %}>

Next, I added the path to the widgets html files in myproject/themes/static_src/tailwind.config.js

module.exports = {
    content: [
        '../templates/**/*.html',
        ...
        '../templates/django/forms/widgets/*.html',

I have a signup form with template: myproject/users/templates/users/signup.html with a {{ form }} tag which generates username, email and password fields (the associated widget types just include widgets/input.html).

This is working fine to style the input widgets, but I also need to add Tailwind styling to their associated label, help text and errors, and I’m having trouble figuring out which templates are being used by Django. For example, for the username input field below, Django is inserting a break and a helptext span, but the generated markup doesn’t seem to match the div.html, the p.html or the table.html.

<label for="id_username">Username:</label>
<input 
  class="mt-1 w-1/2 rounded-md border-indigo-300 shadow-sm
         focus:border-indigo-301 focus:ring focus:ring-indigo-200
         focus:ring-opacity-50" 
  type="text"  name="username"  maxlength="150"  autofocus="" 
  required=""  id="  id_username"
>
<br>
<span class="helptext">Required. 150 characters or fewer. 
     Letters, digits and @/./+/-/_ only.</span>

I tried changing the form tag to {{form.as_div}}, and the form html now does seem to agree with the div.html file in templates/django/forms. I going to copy the rest of the contents of templates/django/forms into my theme templates directory and keep working on this approach, but I’m not sure I’m on the best path here. I’m curious what others who are using Tailwind with Django are doing, and what is recommended by the Django experts here.

I’ve been looking at crispy forms with the tailwind template pack. I’m thinking of giving it a try before going too far down this DIY path.

1 Like

I’m happy with the crispy forms tailwind template pack solution. The forms look great and I’m able to style the whole site with Tailwind (i.e. no other CSS library). The main problem I ran into is that the original ‘django-crispy-forms/crispy-tailwind’ repository has a few pretty significant bugs which haven’t been fixed after a couple years.

These bugs were fixed by several contributors in their own forks, but their pull requests were not accepted by the original maintainers. I ended up re-installing crispy-tailwind from Lewis Fletcher’s fork, GitHub - LewisFletcher/crispy-tailwind: A Tailwind template pack for django-crispy-forms. I did it using the following pip install command:

pip install -e git+https://github.com/LewisFletcher/crispy-tailwind#egg=crispy-tailwind