Custom CSS to Django form inputs

I think rendering an HTML form for you is one of Django's biggest conveniences.

The downside is that the structure of the generated form is not customizable. In case you have a specific design and you need the placement of the inputs at a different position, Django gives you a way to render each element individually at the input control level as follows:

<div class="fieldWrapper">
    {{ form.subject.errors }}
    <label for="{{ form.subject.id_for_label }}">Subject:</label>
    {{ form.subject }}
</div>
template.html

But a customization problem still remains: you cannot set custom classes to the individual input controls. The {{ form.subject }} will render the input control without giving you the chance to set a custom class.

This is problematic because most CSS frameworks (e.g. Bootstrap, Bulma) require you to set specific classes to input controls to style them appropriately.

One solution is to set these classes in the Form object:

class ExampleForm(forms.Form):
   subject = forms.CharField(
       widget=forms.TextInput(attrs={'class':'input-text'}))
   enabled = forms.BooleanField(
       widget=forms.TextInput(attrs={'class':'input-checkbox'}))
forms.py

But in my opinion, this creates a different issue. The Form object is supposed to model the form with its inputs' data types and any other business logic requirements. It's not supposed to be responsible for styling and other visual attributes. The place for such styling instructions is the template.

Unfortunately, I think there's no built-in way of doing this in Django without using an external library. But fear not. There is such a small and lightweight library that does exactly that called django-widget-tweaks.

Using this library you can set custom CSS classes (and more) to your input controls, and you can set this in the template, where all the positioning and styling of the form logically belongs to:

{% load widget_tweaks %}

<div class="fieldWrapper">
    {{ form.subject.errors }}
    <label for="{{ form.subject.id_for_label }}">Subject:</label>
    {{ form.subject|add_class:"input-text" }}
</div>

<div class="fieldWrapper">
    {{ form.enabled.errors }}
    <label for="{{ form.enabled.id_for_label }}">Enabled:</label>
    {{ form.enabled|add_class:"input-checkbox" }}
</div>
template.html

The library offers quite a few more options in customizing form controls. If this has piqued your interest, have a look!

Hopefully, you learned a way to customize Django forms without mixing styling instructions in the Form model.

Happy coding!