Configuration¶
Introduction¶
ProseMirror does a really good job of only allowing content which conforms to a particular scheme. Of course users can submit what they want, they are not constrainted by the HTML widgets you’re using. You should always sanitize the HTML submitted on the server side.
The recommended approach is to use the extensions mechanism for configuring the prose editor field which automatically synchronizes editor extensions with sanitization rules:
from django_prose_editor.fields import ProseEditorField
content = ProseEditorField(
extensions={
"Bold": True,
"Italic": True,
"BulletList": True,
"ListItem": True,
"Link": True,
},
sanitize=True, # Server side sanitization is strongly recommended.
)
This ensures that the HTML sanitization rules exactly match what the editor
allows, preventing inconsistencies between editing capabilities and allowed
output. Note that you need the nh3 library for this which is automatically
installed when you specify the requirement as
django-prose-editor[sanitize].
Overview¶
The editor can be customized in several ways:
Using the new extensions mechanism with
ProseEditorField(recommended).Using the
configparameter to include/exclude specific extensions (legacy approach)Creating custom presets for more advanced customization
Note that the ProseEditorField automatically uses the extension mechanism
when passing extensions and falls back to the legacy behavior otherwise.
Example Configuration¶
The extensions parameter allows you to specify exactly which extensions you
want to enable in your editor:
from django_prose_editor.fields import ProseEditorField
class Article(models.Model):
content = ProseEditorField(
extensions={
# Core text formatting
"Bold": True,
"Italic": True,
"Strike": True,
"Underline": True,
"HardBreak": True,
# Structure
"Heading": {
"levels": [1, 2, 3] # Only allow h1, h2, h3
},
"BulletList": True,
"OrderedList": True,
"ListItem": True, # Used by BulletList and OrderedList
"Blockquote": True,
# Advanced extensions
"Link": {
"enableTarget": True, # Enable "open in new window"
"protocols": ["http", "https", "mailto"], # Limit protocols
},
"Table": True,
"TableRow": True,
"TableHeader": True,
"TableCell": True,
# Editor capabilities
"History": True, # Enables undo/redo
"HTML": True, # Allows HTML view
"SpecialCharacters": True, # Shows nbsp and soft hyphens
}
)
You can also pass additional configurations to extensions:
content = ProseEditorField(
extensions={
"Bold": True,
"Italic": True,
"Heading": {"levels": [1, 2, 3]}, # Only allow H1-H3
"Link": {"enableTarget": False}, # Disable "open in new tab"
}
)
Available extensions include:
Text formatting:
Bold,Italic,Strike,Subscript,Superscript,UnderlineLists:
BulletList,OrderedList,ListItemStructure:
Blockquote,Heading,HorizontalRuleLinks:
LinkTables:
Table,TableRow,TableHeader,TableCellImages and figures:
Figure,Caption(see below)
Check the source code for more!
The extensions which are enabled by default are Document, Paragraph and
Text for the document, Menu, History, Dropcursor and
Gapcursor for the editor functionality and NoSpellCheck to avoid ugly
spell checker interference. You may disable some of these core extensions e.g.
by adding "History": False to the extensions dict.
Common Extension Configurations¶
Django Prose Editor provides special configuration options for common extensions:
Heading Level Restrictions
You can restrict heading levels to a subset of H1-H6:
content = ProseEditorField(
extensions={
"Heading": {
"levels": [1, 2, 3], # Only allow H1, H2, H3
}
}
)
This configuration will only allow the specified heading levels in both the editor and the sanitized output.
Links without ‘open in new tab’ functionality
content = ProseEditorField(
extensions={
"Link": {
"enableTarget": False,
}
}
)
The default is to show a checkbox for this function.
Link Protocol Restrictions
You can restrict which URL protocols are allowed:
content = ProseEditorField(
extensions={
"Link": {
"protocols": ["http", "https", "mailto"], # Only allow these protocols
}
}
)
Figures and Images
The Figure extension allows inserting images optionally wrapped in a
<figure> element with a <figcaption>. Enabling it automatically pulls
in the Image and Caption extensions as well.
content = ProseEditorField(
extensions={
"Figure": True,
}
)
A toolbar button opens a dialog for the image URL and alt text. Once an image
is in the document, a floating bubble menu appears when it is selected,
offering “Add caption” and “Remove caption” actions. Removing the caption from
a figure also removes the <figure> wrapper, leaving a bare <img>.
Figures with a file browser
The pickerUrl option integrates a file browser into the image dialog. A
“Browse…” button will appear next to the URL field and open the file browser
in a popup window.
The file browser endpoint must implement the CKEditor 4 filebrowser protocol:
the editor appends ?CKEditorFuncNum=N to the URL, and the file browser is
expected to call window.opener.CKEDITOR.tools.callFunction(N, url) once a
file has been selected. Despite the name, no actual CKEditor 4 installation is
required — this is simply the protocol that many Django file manager packages
have adopted. Examples include django-cabinet (/admin/cabinet/file/) and
django-filer.
content = ProseEditorField(
extensions={
"Figure": {
"pickerUrl": "/admin/cabinet/file/",
},
}
)
Figure.configure({
pickerUrl: "/admin/cabinet/file/",
})
The file browser may pass an object as a third argument to callFunction.
The dialog fills the alternative text and caption fields from its
alternative_text and caption keys, and stores its id key as a
data-file attribute on the image:
<figure class="figure">
<img src="/media/cabinet/2026/10/image.jpg" alt="..." data-file="42">
<figcaption class="figure-caption">...</figcaption>
</figure>
This allows resolving the file on the server later, e.g. to generate fresh
URLs, other sizes or zoom views, even after the file has been replaced or
renamed. django-cabinet passes the file’s primary key since version 0.20.1.
The attribute is removed when the image URL is changed by hand afterwards, so
it never refers to a different file than src. The sanitizer allows
data-file on img when the Image or Figure extension is
enabled.