Skip to content

Icon Pack Definition

When to Use

You're creating a new icon pack in a theme or module and need the complete YAML structure with all required and optional properties.

Decision

Property Required Use when...
enabled No (defaults true) Conditionally enabling packs
label Recommended, not enforced Display name in admin UI; falls back to the pack ID
description No Explaining pack purpose to site builders
extractor Yes (schema) Always - defines how icons are loaded
config Yes (enforced by the extractor) config: sources for path, svg, svg_sprite, font
template Yes (schema) Always - defines rendered markup
settings No Building an admin settings form for the pack
library No Pack requires CSS/JS
license No Third-party icon sets with licensing
version, links, preview No Metadata and admin previews

icon_pack.schema.json lists only extractor and template under required. label is documented as "Recommended" in the IconPackManager docblock and listIconPackOptions() falls back to the pack ID. config: sources is not in the schema's required list at all — the extractors enforce it themselves and throw IconPackConfigErrorException from checkRequiredConfigSources() when it is missing.

Pattern

Minimal icon pack. Note: no $schema: key — plugin YAML discovery makes every top-level key an icon-pack plugin ID, so a $schema entry breaks discovery for the whole site:

minimal_pack:
  label: "Minimal Icons"
  extractor: svg
  config:
    sources:
      - icons/{icon_id}.svg
  template: >-
    <svg aria-hidden="true" focusable="false">{{ content }}</svg>

Full-featured pack with settings:

full_pack:
  enabled: true
  label: "Full Icon Set"
  description: "Complete icon pack with all options"
  license:
    name: "MIT"
    url: "https://opensource.org/licenses/MIT"
    gpl-compatible: true
  extractor: svg
  config:
    sources:
      - icons/{icon_id}.svg
      - icons/special/{icon_id}-icon.svg
  settings:
    size:
      title: "Size"
      type: "integer"
      default: 24
      minimum: 8
      maximum: 128
    color:
      title: "Color"
      type: "string"
      format: "color"
      default: "currentColor"
  library: "my_theme/icons"
  template: >-
    <svg xmlns="http://www.w3.org/2000/svg"
         width="{{ size|default(24) }}"
         height="{{ size|default(24) }}"
         fill="{{ color|default('currentColor') }}"
         class="icon icon-{{ icon_id|clean_class }}"
         aria-hidden="true"
         focusable="false">
      {{ content }}
    </svg>

Note that in the example above, size: default: 24 and color: default: "currentColor" are form defaults only. Core never merges them into the template context — that is why the template repeats them with |default(24) and |default('currentColor'). Core states this explicitly: "default: (mixed) Form default value, will not be used as default value in the template, template must use |default() twig filter" (IconPackManager.php:103-104). Keep the two in sync by hand.

Reference: /core/assets/schemas/v1/icon_pack.schema.json for the complete schema (metadata.schema.json beside it is the SDC component schema — a different thing).

Common Mistakes

  • Adding $schema: to *.icons.yml → Fatal at discovery, and the URL usually cited points at the SDC schema anyway
  • Missing extractor or templateIconPackConfigErrorException when json-schema validation is available; without it, IconExtractorBase::createIcon() throws "Missing template in your definition" at render time instead
  • Expecting settings: default: to reach the template → It never does; always mirror it with |default() in the template
  • Template without accessibility → Include aria-hidden="true" for decorative icons
  • GPL-incompatible licenses → Set gpl-compatible: false for non-compatible licenses

See Also