Icons are inline SVG elements wrapped in a container class. They inherit colour from the surrounding text, maintain a fixed square aspect ratio, and are accessible by default.
Principles
- Inline SVG only: never use
<img>tags for icons. Inline SVGs allow colour inheritance and eliminate extra HTTP requests. currentColoralways: all icon<path>elements must usefill="currentColor"so the icon inherits the parent's text colour. This keeps icons visually consistent across themes and contexts.- No
xmlns: stripxmlnsandxmlns:xlinkattributes from inline SVGs. They are only needed for standalone files, not inline usage. - Square aspect ratio: icons are always 1:1. Use
viewBoxto define the coordinate system, notwidth/height. - Brand icons only: do not use Material Design, Font Awesome, Heroicons, Feather, or any other third-party icon source. Use the brand icons from
assets/images/svg-icons/. If no icon exists for your need, request one from the design team.
Icon Wrapper
Use to wrap inline SVG icons. This class constrains the icon to a fixed size and enforces the square aspect ratio.
<div class="svg-icn" data-icon="arrow-right">
<svg width="100%" height="100%" viewBox="0 0 24 24" fill="none">
<path d="M5 12h14M12 5l7 7-7 7" fill="currentColor"/>
</svg>
</div>
Properties
| Property | Value | Purpose |
|---|---|---|
width |
1.5rem |
Standard icon size |
height |
1.5rem |
Matches width for square |
display |
flex |
Enables centering |
justify-content |
center |
Horizontal centering |
align-items |
center |
Vertical centering |
aspect-ratio |
1 / 1 |
Enforces square shape |
data-icon attribute
Always include a data-icon attribute with a descriptive name. This makes icons identifiable in code. Raw SVG paths are unreadable without it.
<div class="svg-icn" data-icon="chevron-down">...</div>
<div class="svg-icn" data-icon="close">...</div>
<div class="svg-icn" data-icon="search">...</div>
Use lowercase kebab-case for icon names (e.g. arrow-right, chevron-down, arrow-top-right).
Logos
Logos follow the same data-attribute pattern as icons, using data-logo instead of data-icon. The wrapper uses a generic class, and the logo name goes on the <svg> element.
<div class="svg-logo" style="aspect-ratio: 1050 / 505">
<svg data-logo="by-default-centered" viewBox="0 0 1050 505" width="100%" height="100%" fill="none" aria-hidden="true">
<path d="..." fill="currentColor"/>
</svg>
</div>
Key differences from icons
| Icons | Logos | |
|---|---|---|
| Wrapper class | ||
| Data attribute | data-icon="name" |
data-logo="name" |
| Aspect ratio | Fixed 1:1 via CSS | Preserved via inline style="aspect-ratio: W / H" |
| Size | Fixed (1.3rem default) | Responsive (width set by context) |
CSS targeting
Use :has() to target the wrapper based on a specific logo:
.svg-logo:has([data-logo="by-default-centered"]) {
width: var(--sidebar-logo-width);
}
SVG Cleaner workflow
node assets/js/svg-clean.js --logo --logo-name brand-name --current-color --strip-comments
This outputs a <div class="svg-logo"> wrapper with data-logo="brand-name" on the <svg> element.
Icon in Buttons
For icon-only buttons, add the data-icon-only attribute and as the SVG wrapper. Always include aria-label.
<button class="button" data-icon-only aria-label="Close">
<div class="svg-icn">
<svg width="100%" height="100%" viewBox="0 0 24 24" fill="none">
<path d="M18 6L6 18M6 6l12 12" fill="currentColor"/>
</svg>
</div>
</button>
See the Button documentation for full button modifier details.
SVG Requirements
Every icon SVG must follow these rules before being added to the codebase:
| Rule | Required | Example |
|---|---|---|
fill="currentColor" |
Yes | Inherits text colour from parent |
viewBox attribute |
Yes | viewBox="0 0 24 24" defines the coordinate space |
No xmlns |
Yes | Strip xmlns and xmlns:xlink, not needed inline |
width="100%" height="100%" |
Yes | SVG fills its wrapper; sizing is controlled by the wrapper class |
fill="none" on <svg> |
Yes | Prevents default black fill; paths use fill="currentColor" individually |
| No XML comments | Recommended | Remove <!-- ... --> comments for cleaner code |
Standard viewBox
Use 0 0 24 24 as the default icon grid. If an icon uses a different coordinate system, preserve its original viewBox. Do not rescale manually.
Icon Sprite
Products consuming the system as a package receive the whole registry as one file: icons.svg, a <symbol> sprite built from every icon in assets/images/svg-icons/. It ships alongside design-system.css in the design-system-dist artefact repo.
Symbol ids are the lowercase kebab-case icon names from the registry below — arrow-right, sidebar-left-open, and so on. Reference a symbol with <use> inside the standard wrapper:
<div class="svg-icn" data-icon="arrow-right">
<svg fill="none" width="100%" height="100%" aria-hidden="true">
<use href="/assets/icons/icons.svg#arrow-right"></use>
</svg>
</div>
Two rules carry over unchanged: the wrapper still controls sizing, and icons still inherit colour through currentColor. One new constraint: <use href> does not load cross-origin, so serve the sprite from your own domain — copy it into your project rather than hotlinking it.
Inside this repo, icons stay inline (the docs pages inline each SVG directly); the sprite is the delivery format for package consumers.
Accessibility
- Decorative icons: add
aria-hidden="true"to the SVG when the icon is purely visual and accompanied by text. - Meaningful icons: add
aria-labelto the parent element (e.g. the button) when the icon conveys meaning without visible text. - Icon buttons: always include
aria-labelon the<button>element.
<!-- Decorative: icon next to text -->
<div class="svg-icn" data-icon="check">
<svg width="100%" height="100%" viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M20 6L9 17l-5-5" fill="currentColor"/>
</svg>
</div>
<!-- Meaningful: icon button with no visible text -->
<button class="button is-icon" aria-label="Close menu">
<div class="svg-icn">
<svg width="100%" height="100%" viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M18 6L6 18M6 6l12 12" fill="currentColor"/>
</svg>
</div>
</button>
Colour
Icons inherit colour through currentColor. To change an icon's colour, change the text colour of its parent. Never hardcode a fill value.
<!-- Icon inherits the faded text colour -->
<div class="text-faded">
<div class="svg-icn" data-icon="info">
<svg width="100%" height="100%" viewBox="0 0 24 24" fill="none" aria-hidden="true">
<path d="M12 2a10 10 0 100 20 10 10 0 000-20zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z" fill="currentColor"/>
</svg>
</div>
</div>
Icon Shorthand
Use {{icon:name}} in any markdown file processed by the doc generator to render an inline icon. The shorthand is expanded at build time. The actual SVG is read from assets/images/svg-icons/ and injected as a standard wrapper.
{{icon:check}} → renders the check icon
{{icon:arrow-right}} → renders the arrow-right icon
{{icon:t-shirt}} → renders the t-shirt icon
The name must match a key from the icon registry below. If the name is not found, a warning is logged during generation and an HTML comment is output instead.
This shorthand only works in files processed by cms/generator/generate-docs.js. It does not work in standalone HTML pages.
A second placeholder renders the whole set at once: put {{icon-registry}} on a line of its own and the generator expands it into the full registry table. The Registry section below is built this way.
SVG Cleaner Tool
Use the SVG Cleaner to prepare icons before adding them to the codebase. The tool automates the required cleanup:
- Strips
xmlnsattributes - Sets fills to
currentColor(when enabled) - Wraps in with
data-iconattribute (when "Icon" is checked) - Strips XML comments
- Optional minification
For CLI usage:
echo '<svg>...</svg>' | node assets/js/svg-clean.js --current-color --icon --icon-name arrow-right --strip-comments
Naming Conventions
| Convention | Example |
|---|---|
| Lowercase kebab-case | arrow-right, chevron-down |
| Describe the shape, not the function | arrow-right not go-forward |
| Use directional suffixes | chevron-up, chevron-down, chevron-left |
| Use common icon vocabulary | close, search, menu, check, plus, minus |
Rules
| Do | Don't |
|---|---|
Use fill="currentColor" on all paths |
Hardcode hex colours in SVG fills |
| Use to wrap all icons | Use <img> tags for icons |
Include data-icon with a descriptive name |
Leave icons unnamed |
Include aria-hidden="true" on decorative icons |
Omit accessibility attributes |
Include aria-label on icon-only buttons |
Rely on the icon alone to convey meaning |
| Use the SVG Cleaner to prepare icons | Manually edit SVG attributes |
Strip xmlns from inline SVGs |
Keep attributes meant for standalone files |
Use width="100%" height="100%" on SVGs |
Use fixed pixel/rem sizes on the SVG element |
Use fill="none" on the <svg> element |
Omit fill on <svg> (defaults to black) |
| Use wrapper to control icon size | Size icons via width/height on the SVG |
| Check the registry before using any icon | Use external icon libraries as a fallback |
Registry
The full brand icon set. This table is generated at build time from assets/images/svg-icons/, so it always matches the source directory. The data-icon value is the name to use with the wrapper, the shorthand, and the sprite. For a categorised view with copy and download, see the Brand Book iconography page.
| Icon | data-icon |
|---|---|
3d |
|
accessibility |
|
ad-left |
|
ad-right |
|
ad-top |
|
add |
|
ai |
|
ai-chat |
|
ai-large |
|
ar |
|
arrow-down |
|
arrow-left |
|
arrow-right |
|
arrow-top |
|
arrow-top-right |
|
arrow-up |
|
back-arrow |
|
bolt |
|
book |
|
book-1 |
|
book-2 |
|
book-open |
|
bookmark |
|
brand-book |
|
browser |
|
calendar |
|
catalog |
|
chart |
|
chat |
|
check |
|
check-circled |
|
check-squared |
|
checklist |
|
chevron-down |
|
chevron-down-large |
|
chevron-left |
|
chevron-left-large |
|
chevron-right |
|
chevron-right-large |
|
chevron-up |
|
chevron-up-large |
|
circled |
|
click-2 |
|
clock |
|
close |
|
close-circled |
|
close-large |
|
code |
|
cog |
|
copy |
|
credit-card |
|
cursor |
|
cursor-pointer-1 |
|
cursor-pointer-2 |
|
cursor-pointer-3 |
|
cursor-pointer-4 |
|
dark-mode |
|
design |
|
design-system |
|
desktop |
|
docs |
|
download |
|
drag |
|
exclamation |
|
filter |
|
flame |
|
flame-spark |
|
folder |
|
font-size |
|
frame |
|
full-screen |
|
game |
|
gamepad |
|
globe |
|
headphones |
|
heart |
|
home |
|
icon |
|
info |
|
instagram |
|
light-mode |
|
link |
|
linkedin |
|
list |
|
lock |
|
login |
|
logout |
|
mail |
|
mail-1 |
|
map |
|
menu |
|
minus |
|
mobile |
|
moon |
|
more-horizontal |
|
more-vertical |
|
news |
|
open-full |
|
page |
|
paintbrush |
|
partner |
|
pause |
|
pencil-draw |
|
percentage |
|
phone |
|
photo |
|
photos |
|
pin |
|
play |
|
play-2 |
|
play-outline |
|
present |
|
question |
|
reddit |
|
refresh |
|
reset |
|
return |
|
return-arrow |
|
scroll-down |
|
search |
|
search-large |
|
send |
|
send-2 |
|
settings |
|
share |
|
share-1 |
|
shop |
|
sidebar-close-2 |
|
sidebar-left-close |
|
sidebar-left-open |
|
sidebar-right-close |
|
sidebar-right-open |
|
smiling |
|
sound |
|
sound-off |
|
sound-on |
|
spotify |
|
squared |
|
stack |
|
status-0 |
|
status-10 |
|
status-100 |
|
status-20 |
|
status-50 |
|
status-75 |
|
status-check |
|
sticky-bottom |
|
sticky-top |
|
sun |
|
sun-1 |
|
sun-2 |
|
switch |
|
t-shirt |
|
tablet |
|
tap-3 |
|
thumbs-down |
|
thumbs-up |
|
tools |
|
trending |
|
unlock |
|
user |
|
users |
|
video |
|
warning |
|
weapon |
|
widgets |
|
youtube |
Requesting a New Icon
If you need an icon that is not in the brand icon set:
- Check the brand book: the icon you need may exist under a different name. See the Visual Identity page for the full icon grid.
- Document the request: describe the concept, intended size, and where it will be used
- Submit to the design team: new icons must match the existing style (24x24 grid, single-colour, rounded corners)
- Do not use a placeholder: wait for the brand icon to be designed rather than shipping with a generic substitute
Maintaining a consistent icon language across the site is more important than shipping fast with mismatched icons.