Configuring Rich Text Blocks for Your Wagtail Site
Introduction
Rich text blocks are the most fundamental building block in any Wagtail site. It's important to get the structure right before building out the site, changing it later is going to require re-entering all of your rich text content. In this blog, I'll go through making some changes to Wagtail's built-in Draftail rich text editor:
- By default, the toolbar is not sticky, which can be an inconvenience on long blocks - a simple CSS trick can be used to fix this.
- You can make your code a lot tidier and standardised by defining the feature set as editors, using the little-known WAGTAILADMIN_RICH_TEXT_EDITORS setting.
- Some useful features are missing from the built-in options. You can add these and your own custom features by extending the WSIWYG editor with your own additional custom features which I will go through in more detail in the following Extending the Draftail Editor series.
Set a Floating Toolbar on the Draftail Editor
Not to be confused with the 'floating' (i.e. hidden) toolbar introduced in Wagtail 4.0, this refers to ensuring the toolbar is always visible as the Draftail editor scrolls off the top of the screen. It's a pain to have to scroll up and down to access a formatting button on long text blocks.
Add the following class tweak to your admin site's CSS to make the toolbar float at the top of the screen until the rich text area scrolls out of view.
.Draftail-Toolbar {
/* float toolbar so always visible */
position: sticky !important;
top: calc(0.2rem + 50px) !important;
z-index: 2 !important;
}
@media screen and (max-width: 800px) {
.Draftail-Toolbar {
/* double top height when top menu wraps at 800px */
top: calc(0.2rem + 100px) !important;
}
}
Setting the Draftail Toolbar to Pinned as Default
Wagtail 4.0 & 4.1 were released with a minimalistic draftail interface - toolbar hidden until you highlight text or add a "/" to an empty line ... I find it unusable myself, as did everyone I did UAT with. This was reversed in 4.2. I highly recommend upgrading from either of those two versions.
From Wagtail 4.2 the sticky toolbar was reintroduced as an option. Draftail now comes with the ability to pin the toolbar inside the rich text editor once again (look for the pin icon in the top right of the floating toolbar
).The setting is stored locally in the browser as wagtail:draftail-toolbar = sticky
once pinned, and wagtail:draftail-toolbar = floating
. To view the setting in your browser, with a page open for editing, open the dev tools panel and go to Storage > Local Storage > Website address.
Before being set the first time, there is no stored setting. We can use this as a test and set the toolbar to sticky (i.e. pinned) as the default by including the following in your admin JavaScript:
if (window.localStorage.getItem("wagtail:draftail-toolbar")==null) {
window.localStorage.setItem("wagtail:draftail-toolbar", "sticky");
};
Improve Draftail Toolbar Grouping
The toolbar buttons are grouped together in sets with class Draftail-ToolbarGroup
. The display settings are such that the group will wrap as one instead of the individual buttons leading to some crazy stacking. Add the following class tweak to your admin css to fix that:
.Draftail-ToolbarGroup, .tab-content--comments-enabled .Draftail-CommentControl {
/* allow toolbar button groups to wrap */
display: contents !important;
}
Draftail Features
RichTextFields
& RichTextBlocks
use a set of 'features' to determine what's available on the editor toolbar. By default, those are:
h1
,h2
,h3
,h4
,h5
,h6
- heading elementsbold
,italic
- bold / italic textol
,ul
- ordered / unordered listshr
- horizontal ruleslink
- page, external and email linksdocument-link
- links to documentsimage
- embedded imagesembed
- embedded media
I take out h1
as (for SEO reasons) this should be reserved for the page title only.
Next, I take out image
and embed
. Embedding graphics and media into rich text can have unexpected behaviour on different layouts and is very difficult to achieve a satisfactory result. Maybe I'm being controversial here, but a text block is for text, it's a straightforward exercise to create blocks for media combined with text that will have predictable responsive results.
Also included, but not by default are:
code
- inline codesuperscript
,subscript
,strikethrough
- text formattingblockquote
- blockquote
The editor features can be altered by declaring the parameter as an array of feature names when creating the class instance, for example:
content = RichTextBlock(features= ['bold', 'italic', 'link'])
Use 'editors' to Pre-define Draftail Feature Sets
Rather than declaring a list of features each time you call RichTextBlock or RichTextField, you can predefine sets of features as editors using the WAGTAILADMIN_RICH_TEXT_EDITORS setting which you define in your base.py
. The feature set defined as default will determine which features are present when calling the block or field without any parameters (e.g. content = RichTextBlock()
).
An example set of editors might be:
WAGTAILADMIN_RICH_TEXT_EDITORS = {
'default': {
'WIDGET': 'wagtail.admin.rich_text.DraftailRichTextArea',
'OPTIONS': {
'features': ['h2', 'h3', 'h4', 'bold', 'italic', 'link', 'ol', 'ul', 'hr']
}
},
'full': {
'WIDGET': 'wagtail.admin.rich_text.DraftailRichTextArea',
'OPTIONS': {
'features': ['h2', 'h3', 'h4', 'h5', 'h6', 'bold', 'italic', 'ol', 'ul',
'link', 'hr', 'code', 'document-link', 'blockquote']
}
},
'minimal': {
'WIDGET': 'wagtail.admin.rich_text.DraftailRichTextArea',
'OPTIONS': {
'features': ['bold', 'italic', 'link']
}
},
}
Now, for example, you can call a RichTextBlock
with minimal features with
content = RichTextBlock(editor='minimal')
This provides a much more concise way to call rich text areas and also means you keep your settings centrally and easily manageable, rather than needing to update code in multiple areas of your site.
Adding Features to the Draftail Editor
You can add features to the built-in draftail editor through the use of Wagtail hooks. Covering what hooks are is beyond this article. Suffice to say that they're bits of code that can be run in response to certain events being triggered.
In this case, we use a hook to register a new feature for the editor by creating a custom plugin.
There are three types of plugins that can be created:
- Inline styles – To format a portion of a line, eg.
bold
,italic
,monospace
. - Blocks – To indicate the structure of the content, eg.
blockquote
,ol
. - Entities – To enter additional data/metadata, eg.
link
(with a URL),image
(with a file).
More information and examples can be found in the next blog post, on the Wagtail Documentation article Extending the Draftail Editor and on the Draftail documentation site. The documentation isn't great, so there's a fair amount of experimentation and discovery in dusty corners of StackOverflow to be done.
Conclusion
In this article, I showed how to make the Draftail editor toolbar sticky, how to use the WAGTAILADMIN_RICH_TEXT_EDITORS
setting to define editors with feature sets and introduced how to add new features.
In the following "Extending the Draftail Editor" series I'll cover:
- How to add inline styles to the editor interface using both element tags and custom styles, how to use a unicode glyph label as a button icon, and then create a freeform icon using the path of an svg file.
- How to block styles and give two options for approaching the issue of adding text alignment to your rich text areas. Which route you choose has a big impact on your data structure. Ideally, you should choose which before building out your content. Migrating from one to the other could require a fair amount of work.
- Enabling dynamic inline text using a dummy element class and JavaScript.