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
"Typographic": True, # Enables typographic chars
}
)
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/",
},
}
)