Introduction
Django Unfold provides a comprehensive set of custom form widgets that are styled to match the admin interface. All widgets come with pre-applied Tailwind CSS classes and are fully compatible with Django’s form system.
Text Input Widgets
UnfoldAdminTextInputWidget
Standard text input field with Unfold styling:
from django import forms
from unfold.widgets import UnfoldAdminTextInputWidget
class ArticleForm ( forms . ModelForm ):
title = forms.CharField(
widget = UnfoldAdminTextInputWidget( attrs = {
'placeholder' : 'Enter article title'
})
)
With Prefix and Suffix
# Text prefix
forms.CharField(
widget = UnfoldAdminTextInputWidget( attrs = {
'prefix' : '$' ,
'placeholder' : '0.00'
})
)
# Icon prefix
forms.CharField(
widget = UnfoldAdminTextInputWidget( attrs = {
'prefix_icon' : 'search' ,
'placeholder' : 'Search...'
})
)
# Text suffix
forms.CharField(
widget = UnfoldAdminTextInputWidget( attrs = {
'suffix' : 'kg' ,
'placeholder' : 'Weight'
})
)
# Icon suffix
forms.CharField(
widget = UnfoldAdminTextInputWidget( attrs = {
'suffix_icon' : 'email' ,
'placeholder' : 'Email address'
})
)
Icons use Material Symbols. The widget automatically adjusts padding when icons are present.
Email input with validation:
from unfold.widgets import UnfoldAdminEmailInputWidget
email = forms.EmailField(
widget = UnfoldAdminEmailInputWidget( attrs = {
'placeholder' : '[email protected] '
})
)
URL input with validation:
from unfold.widgets import UnfoldAdminURLInputWidget
website = forms.URLField(
widget = UnfoldAdminURLInputWidget( attrs = {
'placeholder' : 'https://example.com'
})
)
UUID input field:
from unfold.widgets import UnfoldAdminUUIDInputWidget
uuid_field = forms.UUIDField(
widget = UnfoldAdminUUIDInputWidget()
)
Color picker input:
from unfold.widgets import UnfoldAdminColorInputWidget
color = forms.CharField(
widget = UnfoldAdminColorInputWidget()
)
Integer input field:
from unfold.widgets import UnfoldAdminIntegerFieldWidget
age = forms.IntegerField(
widget = UnfoldAdminIntegerFieldWidget( attrs = {
'min' : '0' ,
'max' : '120'
})
)
Big integer field for large numbers:
from unfold.widgets import UnfoldAdminBigIntegerFieldWidget
population = forms.IntegerField(
widget = UnfoldAdminBigIntegerFieldWidget()
)
Decimal number input:
from unfold.widgets import UnfoldAdminDecimalFieldWidget
price = forms.DecimalField(
widget = UnfoldAdminDecimalFieldWidget( attrs = {
'step' : '0.01' ,
'placeholder' : '0.00'
})
)
Range widget with min and max inputs:
from unfold.widgets import UnfoldAdminIntegerRangeWidget
age_range = forms.Field(
widget = UnfoldAdminIntegerRangeWidget()
)
Textarea Widgets
UnfoldAdminTextareaWidget
Multi-line text input:
from unfold.widgets import UnfoldAdminTextareaWidget
description = forms.CharField(
widget = UnfoldAdminTextareaWidget( attrs = {
'rows' : 5 ,
'placeholder' : 'Enter description'
})
)
UnfoldAdminExpandableTextareaWidget
Auto-expanding textarea:
from unfold.widgets import UnfoldAdminExpandableTextareaWidget
comment = forms.CharField(
widget = UnfoldAdminExpandableTextareaWidget( attrs = {
'placeholder' : 'Add a comment'
})
)
The expandable textarea automatically adjusts its height as the user types.
Dropdown select field:
from unfold.widgets import UnfoldAdminSelectWidget
CATEGORY_CHOICES = [
( 'tech' , 'Technology' ),
( 'sports' , 'Sports' ),
( 'news' , 'News' ),
]
category = forms.ChoiceField(
choices = CATEGORY_CHOICES ,
widget = UnfoldAdminSelectWidget()
)
Multiple select field:
from unfold.widgets import UnfoldAdminSelectMultipleWidget
tags = forms.MultipleChoiceField(
choices = TAG_CHOICES ,
widget = UnfoldAdminSelectMultipleWidget()
)
Select for nullable boolean fields:
from unfold.widgets import UnfoldAdminNullBooleanSelectWidget
is_active = forms.NullBooleanField(
widget = UnfoldAdminNullBooleanSelectWidget()
)
Select2-powered autocomplete:
from unfold.widgets import UnfoldAdminSelect2Widget
country = forms.ChoiceField(
choices = COUNTRY_CHOICES ,
widget = UnfoldAdminSelect2Widget()
)
Multiple select with autocomplete:
from unfold.widgets import UnfoldAdminSelect2MultipleWidget
languages = forms.MultipleChoiceField(
choices = LANGUAGE_CHOICES ,
widget = UnfoldAdminSelect2MultipleWidget()
)
AJAX autocomplete widget:
from unfold.widgets import UnfoldAdminAutocompleteWidget
city = forms.ChoiceField(
widget = UnfoldAdminAutocompleteWidget()
)
Multiple selection with AJAX autocomplete:
from unfold.widgets import UnfoldAdminMultipleAutocompleteWidget
cities = forms.MultipleChoiceField(
widget = UnfoldAdminMultipleAutocompleteWidget()
)
Autocomplete widgets require proper AJAX endpoint configuration. See the Custom Fields documentation for model-based autocomplete.
Date picker widget:
from unfold.widgets import UnfoldAdminDateWidget
birthdate = forms.DateField(
widget = UnfoldAdminDateWidget( attrs = {
'placeholder' : 'YYYY-MM-DD'
})
)
Time picker widget:
from unfold.widgets import UnfoldAdminTimeWidget
appointment_time = forms.TimeField(
widget = UnfoldAdminTimeWidget( attrs = {
'placeholder' : 'HH:MM:SS'
})
)
Horizontal date and time picker:
from unfold.widgets import UnfoldAdminSplitDateTimeWidget
published_at = forms.DateTimeField(
widget = UnfoldAdminSplitDateTimeWidget()
)
Vertical date and time picker with custom labels:
from unfold.widgets import UnfoldAdminSplitDateTimeVerticalWidget
event_datetime = forms.DateTimeField(
widget = UnfoldAdminSplitDateTimeVerticalWidget(
date_label = 'Event Date' ,
time_label = 'Event Time'
)
)
Standalone date widget without time shortcuts:
from unfold.widgets import UnfoldAdminSingleDateWidget
date_field = forms.DateField(
widget = UnfoldAdminSingleDateWidget()
)
Standalone time widget:
from unfold.widgets import UnfoldAdminSingleTimeWidget
time_field = forms.TimeField(
widget = UnfoldAdminSingleTimeWidget()
)
Checkbox widget:
from unfold.widgets import UnfoldBooleanWidget
is_active = forms.BooleanField(
widget = UnfoldBooleanWidget()
)
Toggle switch widget:
from unfold.widgets import UnfoldBooleanSwitchWidget
enable_notifications = forms.BooleanField(
widget = UnfoldBooleanSwitchWidget()
)
Radio button group:
from django.contrib.admin.options import HORIZONTAL , VERTICAL
from unfold.widgets import UnfoldAdminRadioSelectWidget
STATUS_CHOICES = [
( 'draft' , 'Draft' ),
( 'published' , 'Published' ),
( 'archived' , 'Archived' ),
]
# Vertical layout (default)
status = forms.ChoiceField(
choices = STATUS_CHOICES ,
widget = UnfoldAdminRadioSelectWidget()
)
# Horizontal layout
status = forms.ChoiceField(
choices = STATUS_CHOICES ,
widget = UnfoldAdminRadioSelectWidget( radio_style = HORIZONTAL )
)
Checkbox group:
from unfold.widgets import UnfoldAdminCheckboxSelectMultipleWidget
permissions = forms.MultipleChoiceField(
choices = PERMISSION_CHOICES ,
widget = UnfoldAdminCheckboxSelectMultipleWidget()
)
File upload widget:
from unfold.widgets import UnfoldAdminFileFieldWidget
document = forms.FileField(
widget = UnfoldAdminFileFieldWidget()
)
Image upload with preview:
from unfold.widgets import UnfoldAdminImageFieldWidget
profile_picture = forms.ImageField(
widget = UnfoldAdminImageFieldWidget()
)
Image upload with small preview:
from unfold.widgets import UnfoldAdminImageSmallFieldWidget
thumbnail = forms.ImageField(
widget = UnfoldAdminImageSmallFieldWidget()
)
Password input field:
from unfold.widgets import UnfoldAdminPasswordWidget
password = forms.CharField(
widget = UnfoldAdminPasswordWidget()
)
Password field with show/hide toggle:
from unfold.widgets import UnfoldAdminPasswordToggleWidget
password = forms.CharField(
widget = UnfoldAdminPasswordToggleWidget()
)
Raw ID widget for foreign keys:
from django.contrib import admin
from unfold.admin import ModelAdmin
@admin.register (Book)
class BookAdmin ( ModelAdmin ):
raw_id_fields = [ 'author' ] # Automatically uses UnfoldForeignKeyRawIdWidget
Wrapper for related field widgets with add/edit/delete buttons:
# Automatically applied to ForeignKey and ManyToMany fields
# Provides + (add), pencil (edit), and × (delete) buttons
Money field widget (requires django-money):
from unfold.widgets import UnfoldAdminMoneyWidget
price = forms.Field(
widget = UnfoldAdminMoneyWidget()
)
Requires django-money package to be installed:
Location field with map (requires django-location-field):
from unfold.widgets import UnfoldAdminLocationWidget
location = forms.CharField(
widget = UnfoldAdminLocationWidget()
)
Requires django-location-field package to be installed: pip install django-location-field
Dynamic array field with add/remove buttons:
from unfold.contrib.forms.widgets import ArrayWidget
from unfold.widgets import UnfoldAdminTextInputWidget
# With text inputs
tags = forms.Field(
widget = ArrayWidget( widget_class = UnfoldAdminTextInputWidget)
)
# With select dropdowns
categories = forms.Field(
widget = ArrayWidget( choices = CATEGORY_CHOICES )
)
The ArrayWidget allows users to dynamically add and remove items from an array field.
Rich text editor (Trix editor):
from unfold.contrib.forms.widgets import WysiwygWidget
content = forms.CharField(
widget = WysiwygWidget()
)
pip install django - unfold[crispy - forms]
All widgets use consistent CSS classes:
Custom Attributes
You can add custom HTML attributes to any widget:
widget = UnfoldAdminTextInputWidget( attrs = {
'placeholder' : 'Enter value' ,
'maxlength' : '100' ,
'pattern' : '[A-Za-z]+' ,
'title' : 'Only letters allowed' ,
'autocomplete' : 'off' ,
'data-custom' : 'value' ,
})
Next Steps
Custom Fields Learn about enhanced form fields
Conditional Fields Implement conditional field visibility