A dedicated API has been added to allow modules and themes to define icon packs. Within each pack is a series of icons each with a unique identifier that the system can then use. Modules and themes can alter icon packs.
To declare an icon pack, create a EXTENSION_NAME.icons.yml file in the extension's base folder. Each top-level entry in this YAML file defines a new icon pack, as a plugin with YAML discovery.
An icon pack has an extractor, which can take values path, svg or svg_sprite. Modules can add additional extractors by creating an IconExtractor plugin (PHP attribute discovery).
Examples
Simple example with path
fixed_path:
# Use the path extractor.
extractor: path
config:
# One icon per listed source, allowed extensions: svg, png, gif, relative to
# this file or to drupal root if start with a `/`. Remote icons are allowed too
# Format can be mixed but only one template is possible. If same id (name here)
# later will override.
# If an icon does not exist, it will be ignored and a log message will be created.
sources:
- icons/foo.svg
- icons/bar.png
- icons/baz.gif
- /libraries/icons/corge.png
- https://www.drupal.org/files/drupal-wordmark.png
# HTML template used to render the icon. Variables `icon_id`, `source` are
# available, some metadata and an `attributes` object.
template: '<img src="{{ source }}" width="32" height="32" alt="{{ icon_id }}">'
Simple example with svg, settings and wildcard
svg:
label: SVG icons
extractor: svg
config:
sources:
- icons/*.svg
settings:
size:
title: "Size"
type: "integer"
default: 32
# Special settings for color widget.
color:
title: "Color"
type: "string"
format: "color"
# Variable `content` is provided by the svg extractor, as well as populated
# `attributes` based on the svg source file attributes.
template: >-
<svg
{{ attributes
.setAttribute('viewBox', attributes.viewBox|default('0 0 50 50'))
.setAttribute('width', size|default('32'))
.setAttribute('height', size|default('32'))
.setAttribute('fill', color|default('currentColor'))
.setAttribute('aria-hidden', 'true')
}}
>
{{ content }}
</svg>
Simple example with SVG sprite file
svg_sprite:
label: SVG sprite icons
extractor: svg_sprite
config:
sources:
# All sprites are extracted from this SVG, can handle multiple sprites.
- icons/foo_sprite.svg
settings:
size:
title: "Size"
type: "integer"
default: 32
# Template expected for a svg sprite with href.
# @see https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/href
template: >-
<svg
xmlns="https://www.w3.org/2000/svg"
width="{{ size|default(32) }}"
height="{{ size|default(32) }}"
aria-hidden="true"
>
<use href="{{ source }}#{{ icon_id }}"/>
</svg>
Advanced example with metadata
wildcard_path:
# Implicit is always enabled, if false will not be available.
enabled: true
# All possible optional metadata.
label: Wildcards
description: Icons from wildcard path
links:
- https://www.drupal.org
version: 1.0.0
license:
name: GPL-3.0-or-later
url: https://www.gnu.org/licenses/gpl-3.0.html
gpl-compatible: true
# Mandatory values to discover icons.
extractor: path
config:
# Sources from a pattern, `{group}` and `{icon_id}` can be extracted
# Discovery of icons is not recursive, same id will override silently.
sources:
- icons/*.png
- icons/{group}/*.png
- icons/*/{group}/*.png
- icons/extracted/prefix_{icon_id}_suffix.png
# You can define settings that will be available in exposed forms and flow
# through to templates.
settings:
width:
title: "Width"
type: "integer"
default: 32
height:
title: "Height"
type: "integer"
default: 32
alt:
title: "Alt text"
type: "string"
description: "Accessibility alternative text, leave empty for decorative icon."
# Example showing multi-line AND settings as variables.
template: >-
<img
class="icon icon-{{ icon_id|clean_class }}"
src="{{ source }}"
width="{{ width|default(32) }}"
height="{{ height|default(32) }}"
alt="{{ icon_id }}"
>
See documentation on core/lib/Drupal/Core/Theme/Icon/Plugin/IconPackManager.php in the code-base for extended documentation of the various keys and their values. As well as test examples in core/modules/system/tests/modules/icon_test/icon_test.icons.yml.
Render an icon
An icon can be rendered using a new icon render element
$build['icon'] = [
'#type' => 'icon',
'#pack_id' => 'material_symbols',
'#icon_id' => 'home',
'#settings' => [
'size' => 64,
],
];
An icon can also be rendered using a new icon() Twig function:
{{ icon('material_symbols', 'home', {size: 64}) }}
Contrib module
Module UI Icons is leveraging this API to enable Drupal integration.
Overriding icon packs
You can override icon pack definitions in a couple of different ways. The first method takes advantage of the hook_icon_pack_alter provided by the \Drupal\Core\Theme\Icon\Plugin\IconPackManager:
/** * Implements hook_icon_pack_alter(). */ function mymodule_icon_pack_alter(array &$icon_packs): void { $icon_packs['navigation']['settings']['size']['default'] = 24; }
The second method takes advantage of how YAML discovery works. First, find out where the icon pack you are interested in is coming from. Look for a *.icons.yml file. Next, copy that *.icons.yml file to your module or theme, renaming it to match your module or theme. For example, if I wanted to override the navigation icon pack provided by the core Navigation module, I would copy navigation.icons.yml to mytheme.icons.yml. The next step is to make adjustments to mytheme.icons.yml according to the following guidelines:
*.icons.ymlfiles can define more than one icon pack. While you may be targetting a specific icon pack, due to limitations with YAML discovery, you'll need to override all icon packs defined.- Adjust the
[icon_pack_id].config.sourcesvalue. Copy paste the icons from where the icon pack was originally defined to your theme as a starting point. The filenames are important and need to remain the same. - Overwrite any specific icon files (or sprites within sprites) that you wish to override.