How do I add a placeholder on a CharField in Django?

This is a popular question since the Django documentation doesn't address this concern directly.

The general question is:

How do I add custom HTML attributes to any form field in Django?

In this post, I'd give you multiple answers to the above question.

The Problem

Consider the form:

class SearchForm(forms.Form):  
    q = forms.CharField()

By default, it renders the input tag:

<input id="id_q" name="q" type="text" required />  

The problem is how to do you get it to render the input tag with other HTML attributes like autofocus, placeholder and class:

<input class="search field" id="id_q" name="q" placeholder="Search GitHub" type="text" autofocus required />  

Solution #1

Replace the default widget.

A widget is Django's representation of a field as an HTML element.

Hence, if you want to customize how a field is rendered you usually need to fiddle with it's widget.

Every widget has an attrs attribute that is a dictionary containing HTML attributes to be set when it is rendered.

You can populate the attrs attribute when instantiating a widget.

So, to solve your problem you can do the following:

class SearchForm(forms.Form):  
    q = forms.CharField(
            widget=forms.TextInput(
                attrs={
                    'autofocus': True,
                    'class': 'search field',
                    'placeholder': 'Search GitHub'
                }
            )
        )

Solution #2

Customize the default widget.

The default widget class for a CharField is TextInput. Hence, you don't need to instantiate a new TextInput just to change attrs. You can access the existing instance and update its attrs attribute.

Here's how you do it:

class SearchForm(forms.Form):  
    q = forms.CharField()

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.fields['q'].widget.attrs.update({
            'autofocus': True,
            'class': 'search field',
            'placeholder': 'Search GitHub'
        })

Solution #3

If you're dealing with a ModelForm then the previous two solutions will work since a ModelForm is a Form. But, you also have the option to specify a custom widget for a field by setting the widgets attribute of the inner Meta class.

class CommentForm(forms.ModelForm):  
    class Meta:
        model = Comment
        widgets = {
            'body': forms.Textarea(attrs={'cols': 80, 'rows': 20})
        }

Conclusion

In conclusion, if you ever need to add custom HTML attributes to a form field in Django then you either need to replace its default widget or customize its default widget.

And, in general, whenever you need to change the visual representation of a form field look to its widget for guidance.

Further reading:

I hope this post has been helpful. Let me know in the comments below which solution you prefer and why.

P.S. Subscribe to my newsletter if you're interested in getting exclusive Django content.