Adding Custom CSS Classes to Django Forms

Django’s form rendering system facilitates seamless styling of forms through the incorporation of custom CSS classes. This not only grants enhanced control over the presentation layer but also enables extensive customization without necessitating alterations to the Python code. In the following discussion, we will delve into the diverse methods at your disposal for seamlessly appending custom classes to both forms and individual form fields within the Django framework.

Why Add Custom Classes?

There are several reasons you may want to add custom CSS classes to your Django forms:

  • Design Flexibility: Custom classes give more control over styling and layout without editing the Python. You can create reusable CSS rules that can be applied to multiple forms.
  • Semantic Markup: Classes allow you to add more semantic meaning through names like “.login-form” or “.required-field”. This improves accessibility.
  • JavaScript Hooks: Custom classes can act as JavaScript selectors to add interactive behavior with libraries like jQuery.
  • Validation Styling: Classes can provide visual feedback on valid/invalid fields. For example, .field-error.

Use Form Media for Global Changes

The easiest way to add classes is through the form’s Media inner class. Setting the css property allows globally applying CSS rules to all fields:

class ContactForm(forms.Form):

  class Media:
    css = {
      "all": ("custom_styles.css",) 

This approach is ideal for sitewide changes like styles on all inputs or textareas. However, it lacks specificity compared to other methods.

Add Custom Classes to Individual Fields

For more precise control, classes can be directly added to form fields. Set the widget arguments on fields:

subject = forms.CharField(
  widget=forms.TextInput(attrs={"class": "form-control"})

This will render like:

<input type="text" name="subject" class="form-control">

This applies only to that field, allowing different styling for each.

Use Django Templates

Classes can also be added when rendering the form template. For example in the template:

{{ form.subject|add_class:"form-control" }}

This keeps presentation separate from Python code. It also allows changing classes depending on other factors in the template’s logic. However, it can lead to redundant markup.

Subclass Widgets

For maximum configurability and reuse, you can subclass widget types like `TextInput` and configure default classes:

class CustomTextInput(forms.TextInput):
    def __init__(self, *args, **kwargs):
        super().__init__(attrs={'class': 'text-input-class'}, *args, **kwargs)

Then set any fields to use the custom widget:

subject = forms.CharField(widget=CustomTextInput)

This approach lets you define custom widgets for common styling needs that can be reused.

Leverage Form Themes

For large projects, Django CSS frameworks like django-widget-tweaks allow defining “form themes” with default class names and CSS files to style multiple forms consistently. This keeps styling abstracted away from code and avoids repeating HTML attributes.


Adding custom CSS classes provides greater style control over Django forms without changing backend code. The right approach depends on the specificity needed – from broad global changes to granular individual field control. Combining these methods gives the flexibility to craft custom interfaces with semantic names, validation states, and interactive widgets using JavaScript. Mastering form styling this way is a must for versatile and professional designs in Django applications.