Skip to content

Commit afddabf

Browse files
Fix React icon rendering in published consumers (#203)
* fix(react-components): inline bundled icons for consumers Switch the default icon path away from bundled data URL <use> references so published consumers render icons reliably. Remove the public React spritePath API while keeping toolkit-backed icon rendering bundled by default. * test(example-react-consumer-app): expand consumer smoke coverage Update the packaged consumer app to exercise direct icons, Select, Card metadata icons, and checkbox ticks against the published tarball install contract. * docs: prep react-components 0.8.0 icon release Bump the React package version, add migration notes for the spritePath removal, and clarify the toolkit hosted-sprite contract versus the React bundled-icon contract. * fix(react-components): satisfy icon lint cleanup Replace the temporary destructuring-based spritePath strip with delete-on-copy so the legacy prop cleanup still works without triggering the repo's unused-vars rule. * fix(icon): address follow-up PR feedback Align the example consumer app colours to design-system token values, add unknown-icon coverage, and make bundled sprite parsing less format-sensitive.
1 parent aaf4962 commit afddabf

File tree

21 files changed

+415
-83
lines changed

21 files changed

+415
-83
lines changed

CHANGELOG.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,18 @@ We are following [Semantic Versioning](https://semver.org/spec/v2.0.0.html), as
66

77
## Monorepo Package Releases (`toolkit-v*`, `react-v*`)
88

9+
### Unreleased
10+
11+
#### @ourfuturehealth/react-components 0.8.0 (`react-v0.8.0`)
12+
13+
##### ⚠️ BREAKING CHANGES
14+
15+
- React `Icon` and `Card` icon configuration no longer accept `spritePath`. React icons now always render from bundled toolkit SVG data.
16+
17+
##### Fixed
18+
19+
- React icons now render correctly in published-consumer installs by inlining the requested bundled SVG symbol instead of referencing a bundled `data:` sprite URL.
20+
921
### 2026-04-09
1022

1123
#### @ourfuturehealth/toolkit 4.9.0 (`toolkit-v4.9.0`)

UPGRADING.md

Lines changed: 60 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,70 @@ This guide provides detailed migration instructions for upgrading between versio
66

77
## Breaking Changes by Version
88

9-
| Version | Date | Breaking Changes | Migration Complexity |
10-
| ------------------------------------------------------- | ------------- | --------------------- | ------------------------------------- |
11-
| [v4.9.0 / React v0.7.0](#upgrading-to-v490--react-v070) | April 2026 | Icon naming sync | 🟡 Medium - Search/replace icon names |
12-
| [v4.8.0 / React v0.6.0](#upgrading-to-v480--react-v060) | March 2026 | No breaking changes | 🟢 Low - only relevant if you adopted the earlier TextInput prototype |
13-
| [v4.7.0 / React v0.5.0](#upgrading-to-v470--react-v050) | March 2026 | Card family realignment | 🟡 Medium - API migration recommended |
14-
| [v4.6.0 / React v0.4.0](#upgrading-to-v460--react-v040) | March 2026 | Tag default + naming | 🟡 Medium - Search/replace recommended |
9+
| Version | Date | Breaking Changes | Migration Complexity |
10+
| ------------------------------------------------------- | ------------- | -------------------------- | ---------------------------------------- |
11+
| [React v0.8.0](#upgrading-to-react-v080) | April 2026 | React `spritePath` removal | 🟢 Low - Remove the deprecated prop |
12+
| [v4.9.0 / React v0.7.0](#upgrading-to-v490--react-v070) | April 2026 | Icon naming sync | 🟡 Medium - Search/replace icon names |
13+
| [v4.8.0 / React v0.6.0](#upgrading-to-v480--react-v060) | March 2026 | No breaking changes | 🟢 Low - only relevant if you adopted the earlier TextInput prototype |
14+
| [v4.7.0 / React v0.5.0](#upgrading-to-v470--react-v050) | March 2026 | Card family realignment | 🟡 Medium - API migration recommended |
15+
| [v4.6.0 / React v0.4.0](#upgrading-to-v460--react-v040) | March 2026 | Tag default + naming | 🟡 Medium - Search/replace recommended |
1516
| [v4.5.0](#upgrading-to-v450) | March 2026 | Spacing and typography API changes | 🟡 Medium - Replace legacy APIs and recheck overrides |
16-
| [v4.3.0 / React v0.2.0](#upgrading-to-v430--react-v020) | March 2026 | Button variant naming | 🟡 Medium - Find/replace required |
17-
| [v4.1.0](#upgrading-to-v410) | February 2026 | Spacing scale indices | 🟡 Medium - Index updates required |
18-
| [v4.0.0](#upgrading-to-v400-monorepo-restructure) | 2025 | Monorepo restructure | 🔴 High - Installation & paths change |
17+
| [v4.3.0 / React v0.2.0](#upgrading-to-v430--react-v020) | March 2026 | Button variant naming | 🟡 Medium - Find/replace required |
18+
| [v4.1.0](#upgrading-to-v410) | February 2026 | Spacing scale indices | 🟡 Medium - Index updates required |
19+
| [v4.0.0](#upgrading-to-v400-monorepo-restructure) | 2025 | Monorepo restructure | 🔴 High - Installation & paths change |
1920

2021
---
2122

23+
## Upgrading to React v0.8.0
24+
25+
**Planned:** April 2026
26+
**Affected packages:**
27+
28+
- `@ourfuturehealth/react-components` v0.8.0+
29+
30+
### Breaking Changes
31+
32+
`@ourfuturehealth/react-components` removes the `spritePath` prop from the public `Icon` API and from `Card` icon configuration. React icons now always render from bundled toolkit SVG data.
33+
34+
### Migration Steps
35+
36+
1. Remove any `spritePath` prop from `Icon` usage.
37+
2. Remove any `spritePath` field from `Card` icon configuration objects.
38+
3. Re-run visual checks for icon-bearing surfaces such as `Icon`, `Select`, `Card`, and `Checkboxes`.
39+
40+
#### React example
41+
42+
**Before:**
43+
44+
```tsx
45+
<Icon name="Search" spritePath="/assets/icons/icon-sprite.svg" />
46+
47+
<Card
48+
icon={{
49+
name: 'Search',
50+
spritePath: '/assets/icons/icon-sprite.svg',
51+
}}
52+
/>
53+
```
54+
55+
**After:**
56+
57+
```tsx
58+
<Icon name="Search" />
59+
60+
<Card
61+
icon={{
62+
name: 'Search',
63+
}}
64+
/>
65+
```
66+
67+
If an application previously passed `spritePath` in React, that prop should now be removed.
68+
69+
### Toolkit reminder
70+
71+
Toolkit/Nunjucks icon consumers are unchanged. They must still serve `icon-sprite.svg` at a public URL, default `/assets/icons/icon-sprite.svg`, or override that URL with `spritePath`.
72+
2273
## Upgrading to v4.9.0 / React v0.7.0
2374

2475
**Released:** April 2026

docs/consuming-react-components.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ The React components package currently provides the following components:
130130
- `CharacterCount` - Text input and textarea variants with count feedback
131131
- `Checkboxes` - Grouped checkbox inputs with hints, exclusive options, and conditional reveals
132132
- `Radios` - Grouped radio inputs with hints and conditional reveals
133-
- `Icon` - Toolkit sprite icon component with fixed and responsive sizing
133+
- `Icon` - Toolkit icon component with fixed and responsive sizing using bundled SVG data
134134
- `ErrorSummary` - Page-level validation summaries with linked errors
135135
- `Tag` - Status tags aligned with toolkit Tag variants
136136
- `Card` - Content presentation cards for summaries, status, and next steps

docs/contributing/material-icons.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ The macro renders:
111111
- An `<svg>` element with `.ofh-icon` classes
112112
- A `<use href="/assets/icons/icon-sprite.svg#ofh-icon-<name>">`
113113

114+
Toolkit consumers must make that sprite file available at a public URL the browser can request. Installing the package places the file in `node_modules/@ourfuturehealth/toolkit/assets/icons/icon-sprite.svg`, but the consuming app still needs to copy or serve it as `/assets/icons/icon-sprite.svg`, or override the URL with `spritePath`.
115+
114116
Example usage:
115117

116118
```njk
@@ -133,7 +135,7 @@ React icon names should stay aligned with toolkit `manifest.json` and the genera
133135
Current React approach:
134136

135137
- Reuses the toolkit sprite semantics (`name`, `size`, responsive sizing, decorative vs titled)
136-
- Defaults to the bundled toolkit sprite asset and references symbols with `<use>`
138+
- Bundles toolkit icon data into the React package and renders the requested symbol inline
137139
- Treats icon-name changes as consumer-facing API changes that must be documented in release notes and the upgrading guide
138140

139141
Related package: [`packages/react-components/`](../../packages/react-components/)

docs/installation/installing-with-npm.md

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Add the dependency to `package.json`:
2727
```json
2828
{
2929
"dependencies": {
30-
"@ourfuturehealth/toolkit": "https://github.com/ourfuturehealth/design-system-toolkit/releases/download/toolkit-v4.0.0/ourfuturehealth-toolkit-4.0.0.tgz"
30+
"@ourfuturehealth/toolkit": "https://github.com/ourfuturehealth/design-system-toolkit/releases/download/toolkit-v{version}/ourfuturehealth-toolkit-{version}.tgz"
3131
}
3232
}
3333
```
@@ -42,7 +42,7 @@ npm install
4242
yarn install
4343
```
4444

45-
Use a specific tag for production upgrades. Replace `4.0.0` with the toolkit version you intend to consume.
45+
Use a specific tag for production upgrades. Replace `{version}` with the toolkit version you intend to consume.
4646

4747
### Unreleased maintainer testing
4848

@@ -67,7 +67,7 @@ You will usually need these pieces:
6767

6868
- [Importing styles](#importing-styles)
6969
- [Importing JavaScript](#importing-javascript)
70-
- [Importing assets (optional)](#importing-assets-optional)
70+
- [Importing assets](#importing-assets)
7171

7272
## Importing styles
7373

@@ -152,10 +152,22 @@ document.addEventListener('DOMContentLoaded', () => {
152152
});
153153
```
154154

155-
## Importing assets (optional)
155+
## Importing assets
156156

157157
Toolkit assets are available under `node_modules/@ourfuturehealth/toolkit/assets/`.
158158

159+
If you use the toolkit `icon` macro or any toolkit component that renders an icon, your app must also publish the sprite file at a browser-visible URL. The default toolkit path is `/assets/icons/icon-sprite.svg`, so the usual setup is to copy:
160+
161+
- `node_modules/@ourfuturehealth/toolkit/assets/icons/icon-sprite.svg`
162+
163+
to:
164+
165+
- `/assets/icons/icon-sprite.svg`
166+
167+
The browser cannot read files directly from `node_modules`, so installing the package is not enough on its own.
168+
169+
If your app serves the sprite from a different public URL, pass that URL to the toolkit icon macro with `spritePath`.
170+
159171
```html
160172
<link rel="shortcut icon" href="path-to-assets/favicons/favicon.ico" type="image/x-icon" />
161173
<link rel="apple-touch-icon" href="path-to-assets/favicons/apple-touch-icon-180x180.png" />

docs/release-versioning-strategy.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ Consumers must install the package release tarball:
6060
```json
6161
{
6262
"dependencies": {
63-
"@ourfuturehealth/toolkit": "https://github.com/ourfuturehealth/design-system-toolkit/releases/download/toolkit-v4.9.0/ourfuturehealth-toolkit-4.9.0.tgz"
63+
"@ourfuturehealth/toolkit": "https://github.com/ourfuturehealth/design-system-toolkit/releases/download/toolkit-v{version}/ourfuturehealth-toolkit-{version}.tgz"
6464
}
6565
}
6666
```
@@ -70,7 +70,7 @@ React consumers follow the same contract:
7070
```json
7171
{
7272
"dependencies": {
73-
"@ourfuturehealth/react-components": "https://github.com/ourfuturehealth/design-system-toolkit/releases/download/react-v0.7.0/ourfuturehealth-react-components-0.7.0.tgz"
73+
"@ourfuturehealth/react-components": "https://github.com/ourfuturehealth/design-system-toolkit/releases/download/react-v{version}/ourfuturehealth-react-components-{version}.tgz"
7474
}
7575
}
7676
```
@@ -126,8 +126,9 @@ This table is a visual aid for pre-monorepo versus post-monorepo releases.
126126
| 17 | `react-v0.5.0` | N/A | `0.5.0` | Monorepo | Released |
127127
| 18 | `toolkit-v4.8.0` | `4.8.0` | N/A | Monorepo | Released |
128128
| 19 | `react-v0.6.0` | N/A | `0.6.0` | Monorepo | Released |
129-
| 20 | `toolkit-v4.9.0` | `4.9.0` | N/A | Monorepo | Planned in this branch |
130-
| 21 | `react-v0.7.0` | N/A | `0.7.0` | Monorepo | Planned in this branch |
129+
| 20 | `toolkit-v4.9.0` | `4.9.0` | N/A | Monorepo | Released |
130+
| 21 | `react-v0.7.0` | N/A | `0.7.0` | Monorepo | Released |
131+
| 22 | `react-v0.8.0` | N/A | `0.8.0` | Monorepo | Planned in this branch |
131132

132133
## References
133134

packages/example-react-consumer-app/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ This app is intentionally configured as a standalone published-consumer example:
77
- it installs the released `@ourfuturehealth/react-components` tarball
88
- it imports the published theme stylesheet bundle
99
- it does not use the monorepo workspace protocol
10+
- it exercises icon-bearing components such as `Icon`, `Select`, `Card`, and `Checkboxes`
11+
12+
The dependency in `package.json` intentionally stays on the current published release tag. For unreleased branch validation, use the local tarball workflow below.
1013

1114
## Install and run
1215

@@ -29,6 +32,7 @@ pnpm dev:react-consumer
2932
- a published tarball install works in a real consumer app
3033
- the exported React components render in a Vite application
3134
- the published stylesheet entrypoints load correctly
35+
- current input-family and icon-bearing components can be smoke-tested outside Storybook
3236

3337
This makes it useful as guidance for future React consumers outside the toolkit repo.
3438

packages/example-react-consumer-app/package-lock.json

Lines changed: 18 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/example-react-consumer-app/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"lint": "eslint . --ignore-pattern '*.config.js'"
1313
},
1414
"dependencies": {
15-
"@ourfuturehealth/react-components": "https://github.com/ourfuturehealth/design-system-toolkit/releases/download/react-v0.5.0/ourfuturehealth-react-components-0.5.0.tgz",
15+
"@ourfuturehealth/react-components": "https://github.com/ourfuturehealth/design-system-toolkit/releases/download/react-v0.7.0/ourfuturehealth-react-components-0.7.0.tgz",
1616
"react": "^19.2.4",
1717
"react-dom": "^19.2.4"
1818
},

0 commit comments

Comments
 (0)