All widgets inherit from the base Widget class.
HTML attributes to add to the rendered widget. Common attributes include class, id, placeholder, etc.
widget = forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'Enter your name',
'maxlength': '100',
})
Whether the widget requires multipart form encoding (e.g., file uploads).
Whether the widget renders as a hidden input.
CSS and JavaScript files required by the widget.
Text Input Widgets
TextInput
Renders an <input type="text"> element.
name = forms.CharField(
widget=forms.TextInput(attrs={'placeholder': 'Full name'})
)
Rendered HTML:
<input type="text" name="name" placeholder="Full name">
Textarea
Renders a <textarea> element.
Default attributes: {'cols': '40', 'rows': '10'}
comment = forms.CharField(
widget=forms.Textarea(attrs={'rows': 5, 'cols': 50})
)
Rendered HTML:
<textarea name="comment" rows="5" cols="50"></textarea>
Renders an <input type="password"> element.
PasswordInput(
attrs=None,
render_value=False
)
Whether to render the value in the password field (not recommended for security).
password = forms.CharField(
widget=forms.PasswordInput()
)
Renders an <input type="hidden"> element.
user_id = forms.IntegerField(
widget=forms.HiddenInput()
)
Renders an <input type="email"> element with HTML5 validation.
email = forms.EmailField(
widget=forms.EmailInput(attrs={'placeholder': '[email protected]'})
)
Renders an <input type="url"> element.
Renders an <input type="number"> element.
Supports min, max, and step attributes:
age = forms.IntegerField(
widget=forms.NumberInput(attrs={'min': '0', 'max': '120'})
)
Renders an <input type="color"> element.
background_color = forms.CharField(
widget=forms.ColorInput()
)
Renders an <input type="search"> element.
Renders an <input type="tel"> element.
Renders a text input for dates.
DateInput(
attrs=None,
format=None
)
Date format string (e.g., '%Y-%m-%d').
birthdate = forms.DateField(
widget=forms.DateInput(attrs={'type': 'date'})
)
Renders a text input for times.
TimeInput(
attrs=None,
format=None
)
appointment = forms.TimeField(
widget=forms.TimeInput(attrs={'type': 'time'})
)
Renders a text input for datetimes.
DateTimeInput(
attrs=None,
format=None
)
published_at = forms.DateTimeField(
widget=forms.DateTimeInput(attrs={'type': 'datetime-local'})
)
Renders separate date and time inputs.
SplitDateTimeWidget(
attrs=None,
date_format=None,
time_format=None,
date_attrs=None,
time_attrs=None
)
Attributes for the date input.
Attributes for the time input.
event = forms.SplitDateTimeField(
widget=forms.SplitDateTimeWidget(
date_attrs={'type': 'date'},
time_attrs={'type': 'time'}
)
)
Renders three select boxes (year, month, day).
SelectDateWidget(
attrs=None,
years=None,
months=None,
empty_label=None
)
List or range of years to display. Defaults to current year + 10 years.
Dictionary mapping month numbers to names.
Label for empty option. Can be a single string or 3-tuple for (year, month, day).
birthdate = forms.DateField(
widget=forms.SelectDateWidget(
years=range(1920, 2024),
empty_label=("Year", "Month", "Day")
)
)
Select
Renders a <select> dropdown.
Select(
attrs=None,
choices=()
)
List of 2-tuples (value, label) for options.
country = forms.ChoiceField(
choices=[('us', 'United States'), ('uk', 'United Kingdom')],
widget=forms.Select(attrs={'class': 'form-select'})
)
Rendered HTML:
<select name="country" class="form-select">
<option value="us">United States</option>
<option value="uk">United Kingdom</option>
</select>
SelectMultiple
Renders a multi-select <select multiple> box.
SelectMultiple(
attrs=None,
choices=()
)
hobbies = forms.MultipleChoiceField(
choices=[('reading', 'Reading'), ('sports', 'Sports'), ('music', 'Music')],
widget=forms.SelectMultiple()
)
RadioSelect
Renders a list of radio buttons.
RadioSelect(
attrs=None,
choices=()
)
STATUS_CHOICES = [
('active', 'Active'),
('inactive', 'Inactive'),
('pending', 'Pending'),
]
status = forms.ChoiceField(
choices=STATUS_CHOICES,
widget=forms.RadioSelect()
)
Rendered HTML:
<div>
<label><input type="radio" name="status" value="active"> Active</label>
<label><input type="radio" name="status" value="inactive"> Inactive</label>
<label><input type="radio" name="status" value="pending"> Pending</label>
</div>
CheckboxSelectMultiple
Renders a list of checkboxes.
CheckboxSelectMultiple(
attrs=None,
choices=()
)
preferences = forms.MultipleChoiceField(
choices=[('email', 'Email'), ('sms', 'SMS'), ('push', 'Push')],
widget=forms.CheckboxSelectMultiple()
)
Renders a single checkbox.
CheckboxInput(
attrs=None,
check_test=None
)
Function that takes a value and returns True if checkbox should be checked.
agree = forms.BooleanField(
widget=forms.CheckboxInput(attrs={'class': 'form-check-input'})
)
NullBooleanSelect
Renders a select with True/False/Unknown options.
NullBooleanSelect(attrs=None)
Options:
"unknown" → Unknown
"true" → Yes
"false" → No
is_active = forms.NullBooleanField(
widget=forms.NullBooleanSelect()
)
Renders an <input type="file"> element.
attachment = forms.FileField(
widget=forms.FileInput(attrs={'accept': '.pdf,.doc,.docx'})
)
File input with option to clear existing file.
ClearableFileInput(attrs=None)
Provides a checkbox to clear the current file value.
avatar = forms.ImageField(
widget=forms.ClearableFileInput()
)
Rendered HTML includes:
- Current file link
- Clear checkbox
- New file input
Base class for widgets composed of multiple widgets.
MultiWidget(
widgets,
attrs=None
)
List or dictionary of widget instances.
Must implement decompress(value) method to split value for sub-widgets.
class SplitNameWidget(forms.MultiWidget):
def __init__(self, attrs=None):
widgets = [
forms.TextInput(attrs={'placeholder': 'First'}),
forms.TextInput(attrs={'placeholder': 'Last'}),
]
super().__init__(widgets, attrs)
def decompress(self, value):
if value:
return value.split(' ', 1)
return ['', '']
Renders multiple hidden inputs for a list of values.
MultipleHiddenInput(attrs=None)
Used automatically for MultipleChoiceField with hidden widget.
Adding CSS Classes
field = forms.CharField(
widget=forms.TextInput(attrs={
'class': 'form-control custom-input',
})
)
Adding Placeholder Text
email = forms.EmailField(
widget=forms.EmailInput(attrs={
'placeholder': '[email protected]',
})
)
Adding Data Attributes
price = forms.DecimalField(
widget=forms.NumberInput(attrs={
'data-currency': 'USD',
'data-precision': '2',
})
)
Disabling Autocomplete
password = forms.CharField(
widget=forms.PasswordInput(attrs={
'autocomplete': 'new-password',
})
)
Adding ARIA Attributes
name = forms.CharField(
widget=forms.TextInput(attrs={
'aria-label': 'Your full name',
'aria-describedby': 'name-help',
})
)
Widgets can declare CSS and JavaScript dependencies:
class CustomWidget(forms.Widget):
class Media:
css = {
'all': ('custom.css',)
}
js = ('custom.js',)
Access in templates:
<head>
{{ form.media.css }}
{{ form.media.js }}
</head>
Or separately:
{{ form.media.css }}
{{ form.media.js }}
Template Rendering
Widgets use Django templates for rendering. Default templates:
django/forms/widgets/text.html
django/forms/widgets/select.html
django/forms/widgets/checkbox.html
- etc.
Customize by overriding template_name:
class CustomTextInput(forms.TextInput):
template_name = 'myapp/widgets/custom_text.html'
Widget Context
Widgets provide context variables to templates:
{
'widget': {
'name': 'field_name',
'value': 'current value',
'attrs': {'class': 'form-control'},
'is_hidden': False,
'required': True,
'template_name': 'django/forms/widgets/text.html',
}
}