Skip to content

Latest commit

 

History

History
184 lines (117 loc) · 6.91 KB

File metadata and controls

184 lines (117 loc) · 6.91 KB

Material icons workflow

This guide explains how to add new Material icons from Figma and how the icon system works.

Quick Start: Adding a New Icon from Figma

Use this checklist when you need to add a new icon:

  1. Get approval and SVG from Design team

    • Confirm the icon is approved for the design system
    • Get the icon name from the Figma layer (should be PascalCase, e.g., AppointmentBooking)
    • Export SVG from Figma at 24x24px
  2. Check and adjust colors

    • Most icons: Replace fill colors with currentColor so they inherit CSS color
    • Brand-colored icons (social media, specific branded icons): Keep original Figma colors (e.g., #011D4B, #FFC62C)
  3. Add the SVG file

    # Save to packages/toolkit/assets/icons/
    # Example: packages/toolkit/assets/icons/AppointmentBooking.svg
  4. Update the manifest

    • Open packages/toolkit/assets/icons/manifest.json
    • Add entry with name (PascalCase), category, and defaultSize:
    {
      "name": "AppointmentBooking",
      "category": "Action",
      "defaultSize": 24
    }
    • Categories: DataValidation, Action, Arrows, Graphical, Stepper, Socials
  5. Rebuild the sprite

    pnpm --filter @ourfuturehealth/toolkit exec node scripts/build-icon-sprite.js
  6. Test and verify

    • Build toolkit: pnpm --filter @ourfuturehealth/toolkit build
    • Run docs locally: pnpm dev:site
    • Check the icon appears at /design-system/styles/icons
    • Use in your component: {{ icon({ "name": "AppointmentBooking", "size": 24 }) }}

Who this guide is for

  • Engineers adding new icons from Figma
  • Engineers consuming toolkit icons in components/templates
  • Maintainers understanding the icon system architecture

Reference: System Architecture

Overview of how the icon system works:

  1. Source files and metadata live in packages/toolkit/assets/icons/.
  2. A build script converts those SVGs into one sprite file: packages/toolkit/assets/icons/icon-sprite.svg.
  3. Toolkit components render icons by name via the icon macro and <use href="...#ofh-icon-name">.
  4. The docs site reads the same manifest and renders the icon gallery from it.

Where the icon assets live

How sprite generation works

The sprite is generated by packages/toolkit/scripts/build-icon-sprite.js:

  • Reads all SVG files from assets/icons
  • Sorts them by filename for deterministic output
  • Converts each file into a <symbol id="ofh-icon-<name>">
  • Writes assets/icons/icon-sprite.svg

Run it directly from repo root:

pnpm --filter @ourfuturehealth/toolkit exec node scripts/build-icon-sprite.js

It also runs automatically in toolkit build via gulp:

Why use a sprite instead of inlining SVG paths everywhere

  • One shared source for icon path data
  • Consistent API (name + size) across components
  • Smaller repeated markup in templates (<use> instead of full path content each time)
  • Easy to update icon internals without touching every component template

How icons are used in toolkit code

Toolkit components use the shared icon macro:

The macro renders:

  • An <svg> element with .ofh-icon classes
  • A <use href="/assets/icons/icon-sprite.svg#ofh-icon-<name>">

Example usage:

{% from 'icon/macro.njk' import icon %}

{{ icon({ "name": "Search", "size": 24, "title": "Search" }) }}

Core icon styles are in packages/toolkit/core/styles/_icons-material.scss and imported in packages/toolkit/core/all.scss.

React components (future)

Current status: the React package does not yet have a shared icon component.

When React icon support is added, this doc should be updated with the final approach. Recommended baseline:

  • Keep icon names aligned with toolkit manifest.json
  • Reuse the same icon semantics (name, size, decorative vs titled)
  • Decide implementation explicitly:
    • Sprite-based <use> approach (consistency with toolkit/docs), or
    • Build-time inlined SVG components

Related package: packages/react-components/

How icons are shown in the documentation site

The docs site does not hardcode the icon list. It reads toolkit manifest data:

Flow:

  1. materialIcons.js loads toolkit/assets/icons/manifest.json
  2. It sorts and groups icons by category
  3. The icons page loops through those groups and calls the shared icon macro

The sprite is copied into docs output by Eleventy:

Troubleshooting & Common Pitfalls

Icon doesn't appear in docs gallery

The sprite builder includes all *.svg files in packages/toolkit/assets/icons/, but the docs gallery reads from manifest.json.

Solution: Ensure the icon has an entry in manifest.json with the exact same name as the SVG filename (without .svg).

New category doesn't show up

New categories need to be added to the category order list.

Solution: Add the category name to packages/site/views/_data/materialIcons.js in the categoryOrder array.

Icon colors don't match Figma

Most icons should use currentColor to inherit CSS colors, but some icons need specific brand colors.

Icons that need brand colors preserved:

  • Social media icons (LinkedIn, X, Facebook, Youtube, Instagram, Tiktok) and their hover states
  • ArrowCircleRightColour (uses #011D4B and #FFC62C)

Solution: For brand-colored icons, keep the original Figma fill colors. For all other icons, replace fill colors with currentColor.

Icon appears broken or misaligned

Check the SVG viewBox and ensure it's exported at the correct size.

Solution: Icons should be exported from Figma at 24x24px with viewBox="0 0 24 24". The sprite builder preserves the viewBox from individual SVG files.