CKEditor 5 Integration
When to Use
Letting authors embed icons inline in body text (e.g., a paragraph with a check mark next to a phrase) without writing markup.
Pattern
Enable ui_icons_ckeditor5 and ui_icons_text.
For each text format that should support icons:
- Configuration → Text formats and editors → {your format} → Configure
- Toolbar: drag the Icon button to the active toolbar
- Filters: enable "Embed icon"
- Save
The Icon button opens a modal picker. On save, an <drupal-icon> tag is inserted:
<drupal-icon
data-icon-id="my_theme_icons:check"
data-icon-settings='{"size":18,"color":"#0a0"}'
class="text-success"
aria-label="Included"
role="img"
></drupal-icon>
The icon_embed text filter transforms the tag at render time using the pack's template.
Where the passthrough attributes actually land
class, aria-label, aria-hidden and role do not reach the element your pack template emits. IconEmbed::getWrappedRenderable() builds the icon renderable, then wraps it in a <span> and puts those attributes there, always appending its own drupal-icon class:
<span class="text-success drupal-icon" aria-label="Included" role="img">
<!-- the pack template's own markup, untouched -->
</span>
It also attaches the ui_icons_text/icon.content library. So style and target .drupal-icon, or the wrapper's own classes — a selector written against the <svg> will not see them.
Two attribute quirks worth knowing:
aria-hiddenis a presence check, not a value check. The filter doesif ($node->getAttribute('aria-hidden')), and the string"false"is truthy in PHP, soaria-hidden="false"becomes booleanTRUEand renders as a bare valuelessaria-hidden. The only way to get a non-hidden icon is to omit the attribute entirely.role="presentation"orrole="none"dropsaria-label. That is deliberate — an element removed from the accessibility tree must not carry an accessible name.
Selecting an inserted icon in the editor opens a balloon toolbar with an Edit button, which reopens the dialog pre-filled from the element's icon id and settings — no need to delete and re-insert to change one.
Pattern: Configuring the text format
ui_icons_text validates the format form and will block the save on three things:
- Allowed HTML. With
filter_htmlenabled, the allowed-tags string must contain<drupal-icon data-icon-id data-icon-settings class aria-label aria-hidden role>. All six attributes are required (or*); a missing one is named in the error. - Filter order.
Embed iconmust run afterfilter_htmlandfilter_autop— that is, at a higher weight. Placing it earlier is a form error. filter_html_escape. If "Display any HTML as plain text" is on, icons cannot work; the validator errors and tells you to remove one or the other.
Decision
| Need | Approach |
|---|---|
| Inline icons in body text | <drupal-icon> filter (this guide) |
| Icons as a separate field | ui_icon field type — see Field API Integration |
| Both | Both — they're independent integrations |
Common Mistakes
- Wrong: enabling the toolbar button without enabling the filter → Right:
<drupal-icon>shows up as raw text in output withouticon_embedenabled - Wrong: putting
Embed iconbeforeLimit allowed HTML tags→ Right: the icon filter consumes the tagfilter_htmlhas already vetted, so it must run after, at a higher weight - Wrong: allowing
<drupal-icon data-icon-id data-icon-settings>only → Right: the format form errors namingclass aria-label aria-hidden roleas missing; the filter needs all six attributes - Wrong: writing
aria-hidden="false"to mark an icon as meaningful → Right: the filter treats any non-empty value as true and emits a barearia-hidden. Omit the attribute instead - Wrong: styling the
<svg>the pack template emits and wondering whereclasswent → Right: it is on the<span class="… drupal-icon">wrapper the filter adds - Wrong: listing only some packs implicitly → Right: restrict via the filter's
allowed_icon_packsetting.result_format(listorgrid) andmax_result(default 24) are settings on the same filter
See Also
- Field API Integration
- UI Icons Overview
- Reference:
modules/ui_icons_text/src/Plugin/Filter/IconEmbed.php - Reference:
modules/ui_icons_ckeditor5/js/ckeditor5_plugins/icon/src/iconToolbar.js