---
title: "The form rendering API"
version: 3.0
locale: en
source: https://docs.djangoproject.com/en/3.0/ref/forms/renderers/
canonical: https://djangodocs.dev/en/3.0/ref/forms/renderers/
---
# The form rendering API

Django’s form widgets are rendered using Django’s [template engines
system](/en/3.0/topics/templates/).

The form rendering process can be customized at several levels:

- Widgets can specify custom template names.
- Forms and widgets can specify custom renderer classes.
- A widget’s template can be overridden by a project. (Reusable applications
  typically shouldn’t override built-in templates because they might conflict
  with a project’s custom templates.)

## The low-level render API

The rendering of form templates is controlled by a customizable renderer class.
A custom renderer can be specified by updating the [`FORM_RENDERER`](/en/3.0/ref/settings/#std-setting-FORM_RENDERER)
setting. It defaults to
`'`[`django.forms.renderers.DjangoTemplates`](#django.forms.renderers.DjangoTemplates)`'`.

You can also provide a custom renderer by setting the
[`Form.default_renderer`](/en/3.0/ref/forms/api/#django.forms.Form.default_renderer) attribute or by using the `renderer` argument
of [`Widget.render()`](/en/3.0/ref/forms/widgets/#django.forms.Widget.render).

Use one of the [built-in template form renderers](#built-in-template-form-renderers) or implement your own. Custom renderers
must implement a `render(template_name, context, request=None)` method. It
should return a rendered templates (as a string) or raise
[`TemplateDoesNotExist`](/en/3.0/topics/templates/#django.template.TemplateDoesNotExist).

## Built-in-template form renderers

### `DjangoTemplates`

#### `class DjangoTemplates`

This renderer uses a standalone
[`DjangoTemplates`](/en/3.0/topics/templates/#django.template.backends.django.DjangoTemplates)
engine (unconnected to what you might have configured in the
[`TEMPLATES`](/en/3.0/ref/settings/#std-setting-TEMPLATES) setting). It loads templates first from the built-in form
templates directory in `django/forms/templates` and then from the installed
apps’ templates directories using the [`app_directories`](/en/3.0/ref/templates/api/#django.template.loaders.app_directories.Loader) loader.

If you want to render templates with customizations from your
[`TEMPLATES`](/en/3.0/ref/settings/#std-setting-TEMPLATES) setting, such as context processors for example, use the
[`TemplatesSetting`](#django.forms.renderers.TemplatesSetting) renderer.

### `Jinja2`

#### `class Jinja2`

This renderer is the same as the [`DjangoTemplates`](#django.forms.renderers.DjangoTemplates) renderer except that
it uses a [`Jinja2`](/en/3.0/topics/templates/#django.template.backends.jinja2.Jinja2) backend. Templates
for the built-in widgets are located in `django/forms/jinja2` and installed
apps can provide templates in a `jinja2` directory.

To use this backend, all the widgets in your project and its third-party apps
must have Jinja2 templates. Unless you provide your own Jinja2 templates for
widgets that don’t have any, you can’t use this renderer. For example,
[`django.contrib.admin`](/en/3.0/ref/contrib/admin/#module-django.contrib.admin) doesn’t include Jinja2 templates for its widgets
due to their usage of Django template tags.

### `TemplatesSetting`

#### `class TemplatesSetting`

This renderer gives you complete control of how widget templates are sourced.
It uses [`get_template()`](/en/3.0/topics/templates/#django.template.loader.get_template) to find widget
templates based on what’s configured in the [`TEMPLATES`](/en/3.0/ref/settings/#std-setting-TEMPLATES) setting.

Using this renderer along with the built-in widget templates requires either:

- `'django.forms'` in [`INSTALLED_APPS`](/en/3.0/ref/settings/#std-setting-INSTALLED_APPS) and at least one engine
  with [`APP_DIRS=True`](/en/3.0/ref/settings/#std-setting-TEMPLATES-APP_DIRS).
- Adding the built-in widgets templates directory in [`DIRS`](/en/3.0/ref/settings/#std-setting-TEMPLATES-DIRS) of one of your template engines. To generate that path:

  ```
  import django
  django.__path__[0] + '/forms/templates'  # or '/forms/jinja2'
  ```

Using this renderer requires you to make sure the form templates your project
needs can be located.

## Context available in widget templates

Widget templates receive a context from [`Widget.get_context()`](/en/3.0/ref/forms/widgets/#django.forms.Widget.get_context). By
default, widgets receive a single value in the context, `widget`. This is a
dictionary that contains values like:

- `name`
- `value`
- `attrs`
- `is_hidden`
- `template_name`

Some widgets add further information to the context. For instance, all widgets
that subclass `Input` defines `widget['type']` and [`MultiWidget`](/en/3.0/ref/forms/widgets/#django.forms.MultiWidget)
defines `widget['subwidgets']` for looping purposes.

## Overriding built-in widget templates

Each widget has a `template_name` attribute with a value such as
`input.html`. Built-in widget templates are stored in the
`django/forms/widgets` path. You can provide a custom template for
`input.html` by defining `django/forms/widgets/input.html`, for example.
See [Built-in widgets](/en/3.0/ref/forms/widgets/#built-in-widgets) for the name of each widget’s template.

To override widget templates, you must use the [`TemplatesSetting`](#django.forms.renderers.TemplatesSetting)
renderer. Then overriding widget templates works [the same as](/en/3.0/howto/overriding-templates/) overriding any other template in your project.
