⚠️ Design system CSS not found. Check the path in cms/docs.config.js → designSystemPath, then re-run npm run docgen.

Icon

Brand icon standards and the full registry

Website / Icon
Download .md file
Open .md in new tab
On this page
  • Principles
  • Icon Wrapper
  • Logos
  • Icon in Buttons
  • SVG Requirements
  • Icon Sprite
  • Icon Manifest & Consumer Sync
  • Accessibility
  • Colour
  • Icon Shorthand
  • SVG Cleaner Tool
  • Naming Conventions
  • Rules
  • Registry
  • Requesting a New Icon

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.
  • currentColor always: all icon <path> elements must use fill="currentColor" so the icon inherits the parent's text colour. This keeps icons visually consistent across themes and contexts.
  • No xmlns: strip xmlns and xmlns:xlink attributes from inline SVGs. They are only needed for standalone files, not inline usage.
  • Square aspect ratio: icons are always 1:1. Use viewBox to define the coordinate system, not width/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

npx svg-cleaner --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.


Icon Manifest & Consumer Sync

Package consumers control which icons they ship via icons.manifest.json at the project root. The bd-sprite CLI — run automatically by bd-sync on install — reads it and builds a project-sized sprite instead of shipping the full master set.

{
  "output": "assets/icons/icons.svg",
  "icons": ["arrow-right", "chevron-down", "close", "check", "search", "menu"],
  "local": ["assets/icons/local"]
}
  • output — where the built sprite lands, relative to the manifest
  • icons — design system icon names to include, matched against the registry below (drop the .svg extension)
  • local — optional list of directories holding the project's own SVGs, merged into the same sprite

When to Subset

Most sites reference 15–45 of the 175 icons in the registry. The sprite carries
177 symbols — the extra two are deprecated names kept resolving for consumers
(icons.aliases.json) and deliberately hidden from the registry. The master sprite — every icon, unfiltered — is roughly 115KB; a subset sprite trims that to just what the site uses.

Situation What to do
Site uses a small, known set of icons Add icons.manifest.json and list them — smallest possible sprite
Site is early, icon usage still shifting Skip the manifest — bd-sync copies the full master sprite by default, no build step required
Site already has a manifest and adds an icon Add the name to icons, re-run bd-sync

Subsetting is opt-in: no manifest, no build. A project that never creates icons.manifest.json gets the full master sprite exactly as it always has.

Site-Local Icons

The local key points at directories of icons the project owns but the design system doesn't — one-off marks with no reason to live in the shared registry. Two rules are enforced at build time, not left to convention:

  • Kebab-case only. A symbol id becomes both an XML attribute and a <use href="#name"> fragment — a name like Frame 1 & 2 produces a sprite no browser can parse, with no error surfaced. Local names must match the same a-z0-9- pattern as design system icons.
  • No collisions with design system names. A local icon named close would shadow the shared close symbol depending on load order — invisible until the wrong icon renders somewhere. The build hard-fails on any collision rather than silently picking a winner.

Both checks are fail-fast by design: a build that quietly resolved the conflict would ship the wrong icon with nothing to chase.

Third-party brand marks are the canonical site-local case. The Google and Apple sign-in marks live at assets/icons/local/ in this repo — deliberately outside the shared registry, because a brand mark is a per-product licensing decision, not a system asset. They follow the same authoring rules as registry icons (24×24, monochrome currentColor paths, cleaned with npx svg-cleaner) and are inlined where used; the {{icon:name}} shorthand reads the shared registry only and will not resolve them. See Login → Social sign-in for usage.

Renamed Icons

An icon name is public API: it appears in consumer icons.manifest.json files this repo can't see. So a rename keeps the old name working rather than breaking those builds silently. The retired name stays on disk as a byte-identical source file and is recorded in icons.aliases.json at the project root:

{
  "aliases": {
    "switch": { "renamedTo": "loop", "since": "2.2.0" }
  }
}

Listed names still build into the sprite and still resolve through a manifest, but they are hidden from the registry table, the Brand Book grid, and llms.txt — one glyph, one name, everywhere a person or a model goes looking. Alias files and their entries are deleted at the next major version.

Duplicate Detection

The docs generator compares the path data of every icon at build time, ignoring coordinate precision, and warns when two names resolve to the same drawing:

⚠️  Duplicate icon geometry: "docs" is the same drawing as "page" — one of them is redundant

Matching filenames were always caught; matching artwork was not, which is how a re-export saved under a new name could quietly become the registry's second copy of an existing icon. The check warns rather than fails — a deliberate near-duplicate is a judgement call, but it should be a conscious one.

Cursor Sprite (Separate Artifact)

dist/cursors.svg ships alongside the icon sprite but is never merged into it. Icon symbols are single-colour (fill="currentColor", inherited from the parent); the cursor glyphs used by bd-cursor's GRAPHIC mode are two-colour — an outline plus a fill — which currentColor can't express. bd-sync copies cursors.svg in full whenever it exists in the release; it isn't affected by icons.manifest.json subsetting, since cursor glyphs were never part of the icon registry to begin with.

Icon Font

SVG sprites are the delivery format for icons in this system. No icon font exists, and none is planned. Every icon source already lives as an individual SVG in assets/images/svg-icons/, so a font is technically possible — it would be generated from that same source folder rather than maintained as a separate asset. That only happens if a real context demands it, such as an email template that can't reference an external sprite via <use>. Until a context like that shows up, sprites stay the only delivery format.


Accessibility

  • Decorative icons: add aria-hidden="true" to the SVG when the icon is purely visual and accompanied by text.
  • Meaningful icons: add aria-label to the parent element (e.g. the button) when the icon conveys meaning without visible text.
  • Icon buttons: always include aria-label on 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 xmlns attributes
  • Sets fills to currentColor (when enabled)
  • Wraps in with data-icon attribute (when "Icon" is checked)
  • Strips XML comments
  • Optional minification

For CLI usage:

echo '<svg>...</svg>' | npx svg-cleaner --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-open
bookmark
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-4
design
design-system
desktop
docs
download
drag
exclamation
eye
eye-off
fast-forward
file
file-audio
file-css
file-doc
file-font
file-html
file-img
file-json
file-md
file-txt
file-video
filter
flame
flame-spark
folder
folder-open
font-size
frame
full-screen
game
gamepad
globe
headphones
heart
home
info
instagram
link
linkedin
list
lock
login
logout
loop
loop-reverse
mail
map
menu
minus
mobile
moon
more-horizontal
more-vertical
news
open-full
paintbrush
partner
pause
pencil
pencil-draw
percentage
photo
photos
pin
play
play-2
play-outline
present
question
reddit
refresh
return-arrow
rewind
scroll-down
search
search-large
send
settings
share
share-1
shop
shopping-bag
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-2
swap
t-shirt
tablet
tap-3
target
thumbs-down
thumbs-up
tiktok
trash
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:

  1. Check the brand book: the icon you need may exist under a different name. See the Visual Identity page for the full icon grid.
  2. Document the request: describe the concept, intended size, and where it will be used
  3. Submit to the design team: new icons must match the existing style (24x24 grid, single-colour, rounded corners)
  4. 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.

On this page
  • Principles
  • Icon Wrapper
  • Logos
  • Icon in Buttons
  • SVG Requirements
  • Icon Sprite
  • Icon Manifest & Consumer Sync
  • Accessibility
  • Colour
  • Icon Shorthand
  • SVG Cleaner Tool
  • Naming Conventions
  • Rules
  • Registry
  • Requesting a New Icon
Previous Border
Next Motion

Was this page helpful?

We use this feedback to improve our documentation.

Thanks for your feedback

Send feedback

© 2026 By Default