This guide provides detailed migration instructions for upgrading between versions of the Design System Toolkit and React Components packages.
Quick reference: Jump to the version you're upgrading from/to below.
| Version | Date | Breaking Changes | Migration Complexity |
|---|---|---|---|
| v4.5.0 / React v0.4.0 | March 2026 | Card family realignment | 🟡 Medium - API migration recommended |
| v4.3.0 / React v0.2.0 | March 2026 | Button naming | 🟡 Medium - Find/replace required |
| v4.1.0 | February 2026 | Spacing scale indices | 🟡 Medium - Index updates required |
| v4.0.0 | 2025 | Monorepo restructure | 🔴 High - Installation & paths change |
Released: March 2026 Affected packages:
@ourfuturehealth/toolkitv4.5.0+@ourfuturehealth/react-componentsv0.4.0+
None.
The Card family has been aligned to the current design-system split:
cardremains the base componentwarning-callouthas moved tocard-calloutdo-dont-listhas moved tocard-do-dont
Existing toolkit consumers should continue to work without immediate code changes:
warningCallout()still renders, but it is deprecatedlist()still renders, but it is deprecated- legacy
cardinputs such asclickable,feature,type, andHTMLstill render, but they are deprecated
For new work, migrate to the new APIs:
| Deprecated toolkit API | Preferred API |
|---|---|
warningCallout() |
cardCallout({ variant: 'warning', ... }) |
| `list({ type: 'tick' | 'cross' })` |
card({ clickable: true }) |
card({ variant: 'clickable' }) |
cardWithIcon() |
card({ icon: { ... } }) |
card({ HTML: ... }) |
card({ descriptionHtml: ... }) |
There was no existing React Card consumer base to migrate, so the React Card family only exposes the new API:
CardCardCalloutCardDoDont
React does not include the deprecated toolkit compatibility props.
Released: March 2026
Affected packages:
@ourfuturehealth/toolkitv4.3.0+@ourfuturehealth/react-componentsv0.2.0+
Button variant naming has been updated to align with Figma design specifications:
| Old Name (Deprecated) | New Name (Required) |
|---|---|
ghost-reverse |
ghost-inverted |
text-reverse |
text-inverted |
All other variants (contained, outlined, ghost, text) remain unchanged.
Why this change? The term "inverted" more accurately describes the visual treatment (inverted colors for dark backgrounds) than "reverse", and aligns with Figma design specifications.
If you're using the toolkit's CSS classes directly in HTML or templates:
Before (toolkit v4.2.0 and earlier):
<button class="ofh-button ofh-button--ghost-reverse">Button</button>
<button class="ofh-button ofh-button--text-reverse">Button</button>After (toolkit v4.3.0+):
<button class="ofh-button ofh-button--ghost-inverted">Button</button>
<button class="ofh-button ofh-button--text-inverted">Button</button>SCSS/CSS overrides:
If you have custom styles targeting these classes:
// ❌ OLD - Update these
.ofh-button--ghost-reverse {
// custom styles
}
.ofh-button--text-reverse {
// custom styles
}
// ✅ NEW - Use these instead
.ofh-button--ghost-inverted {
// custom styles
}
.ofh-button--text-inverted {
// custom styles
}If you're using the React component library:
Before (react-components v0.1.0):
import { Button } from '@ourfuturehealth/react-components';
<Button variant="ghost-reverse">Button</Button>
<Button variant="text-reverse">Button</Button>After (react-components v0.2.0+):
import { Button } from '@ourfuturehealth/react-components';
<Button variant="ghost-inverted">Button</Button>
<Button variant="text-inverted">Button</Button>TypeScript types:
The TypeScript definitions have been updated. Your IDE/compiler will show errors for the old variant names:
// ❌ TypeScript Error - Property '"ghost-reverse"' does not exist in type
type ButtonVariant = 'ghost-reverse' | 'text-reverse';
// ✅ Use the new names
type ButtonVariant = 'ghost-inverted' | 'text-inverted';Use this checklist to ensure you've updated all occurrences:
Run these searches in your project:
# Search for old variant names in all files
grep -r "ghost-reverse" .
grep -r "text-reverse" .
# Search specifically in React/TypeScript files
grep -r "ghost-reverse\|text-reverse" --include="*.tsx" --include="*.ts" --include="*.jsx" --include="*.js" .
# Search in SCSS/CSS files
grep -r "ghost-reverse\|text-reverse" --include="*.scss" --include="*.css" .
# Search in HTML/template files
grep -r "ghost-reverse\|text-reverse" --include="*.html" --include="*.njk" .- React component
variantprops - TypeScript type definitions
- HTML class names
- CSS/SCSS class selectors
- Storybook stories
- Test files
- Documentation
- Design system examples
After updating your code, verify:
- Visual Testing: All buttons render correctly with proper styling
- Functional Testing: Button interactions (click, focus, hover) work as expected
- Accessibility Testing: Focus indicators are visible on all button variants
- Responsive Testing: Buttons behave correctly at different breakpoints
Test all button states for the renamed variants:
-
ghost-inverted- Default, Hover, Active, Focus, Disabled states -
text-inverted- Default, Hover, Active, Focus, Disabled states
feat!: migrate button variants from -reverse to -inverted
BREAKING CHANGE: Update button variant naming to align with Figma
- ghost-reverse → ghost-inverted
- text-reverse → text-inverted
Refs: toolkit v4.3.0, react-components v0.2.0
Released: February 2026
Affected packages:
@ourfuturehealth/toolkitv4.1.0+
The spacing scale now includes a new 2px point at index 1.
To add this new point, spacing indices were shifted by +1 for all existing non-zero values:
0stays01is now2px(new)- Previous
1..Nbecomes2..N+1
ofh-spacing()valid points changed from0-9to0-10- Responsive spacing points changed from
0-10to0-11 - Utility class suffixes for spacing (
ofh-u-margin-*,ofh-u-padding-*) follow the same index shift
Update any spacing indices greater than zero by adding 1:
| Before | After |
|---|---|
ofh-spacing(1) |
ofh-spacing(2) |
ofh-spacing(6) |
ofh-spacing(7) |
@include ofh-responsive-margin(4, 'bottom') |
@include ofh-responsive-margin(5, 'bottom') |
@include ofh-responsive-padding(8, 'top') |
@include ofh-responsive-padding(9, 'top') |
ofh-u-margin-1 |
ofh-u-margin-2 |
ofh-u-padding-top-4 |
ofh-u-padding-top-5 |
ofh-u-margin-10 |
ofh-u-margin-11 |
Important: If you do not update these indices, spacing will render smaller than before.
# Find SCSS function calls
grep -r "ofh-spacing(" --include="*.scss" .
grep -r "ofh-responsive-margin(" --include="*.scss" .
grep -r "ofh-responsive-padding(" --include="*.scss" .
# Find utility classes in templates
grep -r "ofh-u-margin-" --include="*.html" --include="*.njk" .
grep -r "ofh-u-padding-" --include="*.html" --include="*.njk" .Released: February 2026 Affected packages:
- All packages (repository restructured)
The toolkit was restructured from a single-package repository into a monorepo with separate packages. This change improves maintainability and separation of concerns, but requires updates to how consuming projects install and reference the toolkit.
No, existing consumers will NOT automatically break.
If your project uses a version tag from v3.4.3 or earlier, it will continue to work indefinitely:
{
"dependencies": {
"ofh-design-system-toolkit": "github:ourfuturehealth/design-system-toolkit#v3.4.3"
}
}✅ This works forever - Git tags are immutable and point to the pre-refactor code.
You'll need to update your installation syntax if:
| Scenario | Will Break? | When to Update |
|---|---|---|
Using #v3.4.3 or older version tag |
❌ No | Only when you want to upgrade to v4.0.0+ |
Using #main branch (no version) |
✅ Yes | Immediately after merge |
Trying to upgrade to #toolkit-v4.0.0 or newer |
🔄 Yes | Must use new syntax (see below) |
| No version specified in package.json | ✅ Yes | Immediately after merge |
Bottom line: If you're using a version tag from v3.4.3 or earlier, you're safe and can upgrade on your own timeline.
Before v3.4.3 (single-package):
design-system-toolkit/
├── dist/ # Compiled CSS & JS outputs
├── packages/
│ ├── components/ # Component templates & source
│ └── core/ # Core styles & utilities
├── site/ # Documentation site
├── gulpfile.js # Build tasks at root
└── package.json # Single package.json
After v4.0.0 (monorepo structure):
design-system-toolkit/
├── packages/
│ ├── toolkit/ # Design system toolkit package
│ │ ├── dist/ # Compiled CSS & JS outputs
│ │ ├── components/ # Component templates & source
│ │ ├── core/ # Core styles & utilities
│ │ ├── gulpfile.js # Toolkit-specific build tasks
│ │ └── package.json # Toolkit package.json
│ │
│ ├── site/ # Documentation site package
│ │ └── package.json
│ │
│ └── react-components/ # React components package
│ └── package.json
├── pnpm-workspace.yaml # Monorepo workspace config
└── package.json # Root workspace package.json
- Toolkit moved:
packages/components/→packages/toolkit/components/ - Build outputs moved:
dist/→packages/toolkit/dist/ - Separate package.json files: Each package now has its own dependencies and scripts
- Workspace dependencies: Packages reference each other using pnpm workspace protocol
- Independent versioning: Each package can be versioned separately
Before v3.4.3:
{
"dependencies": {
"ofh-design-system-toolkit": "github:ourfuturehealth/design-system-toolkit#v3.4.3"
}
}After v4.0.0:
Install from specific release tag (recommended):
{
"dependencies": {
"@ourfuturehealth/toolkit": "github:ourfuturehealth/design-system-toolkit#toolkit-v4.5.0:packages/toolkit"
}
}Or install from branch:
{
"dependencies": {
"@ourfuturehealth/toolkit": "github:ourfuturehealth/design-system-toolkit#main:packages/toolkit"
}
}Note: The :packages/toolkit suffix is required to install the toolkit package from the monorepo subdirectory.
Before:
{% from 'packages/components/action-link/macro.njk' import actionLink %}
{% from 'packages/components/breadcrumb/macro.njk' import breadcrumb %}
{% from 'packages/components/button/macro.njk' import button %}After:
{% from 'action-link/macro.njk' import actionLink %}
{% from 'breadcrumb/macro.njk' import breadcrumb %}
{% from 'button/macro.njk' import button %}Search your codebase:
# Find all Nunjucks template imports
grep -r "from 'packages/components/" .Update your Eleventy config (or equivalent template engine config):
const nunjucks = require('nunjucks');
module.exports = function configuration(eleventyConfig) {
const nunjucksEnv = nunjucks.configure(
[
'views/',
'views/_includes/',
'node_modules/@ourfuturehealth/toolkit/components/', // ← Add this
'node_modules/@ourfuturehealth/toolkit/',
],
{
watch: false,
noCache: true,
}
);
eleventyConfig.setLibrary('njk', nunjucksEnv);
return {
dir: {
input: 'views/',
output: 'dist/',
},
};
};Before:
// Import from root packages directory
@import 'packages/core/all';
@import 'packages/components/button/button';After:
// Import from toolkit package
@import '@ourfuturehealth/toolkit/ofh.scss'; // All styles
// Or import specific components
@import '@ourfuturehealth/toolkit/core/all';
@import '@ourfuturehealth/toolkit/components/button/button';Update Sass CLI with load paths:
{
"scripts": {
"build:css": "sass --style compressed --load-path ./node_modules/@ourfuturehealth/toolkit ./styles/:./dist/css/"
}
}Before:
import { Button } from '../packages/components/button/button.js';After:
import { Button } from '@ourfuturehealth/toolkit/components/button/button.js';
// Or use the compiled bundle
import '@ourfuturehealth/toolkit/dist/ofh-design-system-toolkit.js';Update paths to compiled CSS and JS files:
Before:
<link rel="stylesheet" href="/design-system-toolkit/ofh-design-system-toolkit.css" />
<script src="/design-system-toolkit/ofh-design-system-toolkit.js"></script>After:
<link
rel="stylesheet"
href="/node_modules/@ourfuturehealth/toolkit/dist/ofh-design-system-toolkit.css"
/>
<script src="/node_modules/@ourfuturehealth/toolkit/dist/ofh-design-system-toolkit.js"></script>Or update your build process to copy from the new location:
// Eleventy passthrough copy
eleventyConfig.addPassthroughCopy({
'node_modules/@ourfuturehealth/toolkit/dist': 'ofh-design-system-toolkit',
'node_modules/@ourfuturehealth/toolkit/assets': 'ofh-design-system-toolkit/assets',
});The toolkit provides three main outputs:
Pre-built, minified files ready for production use:
- CSS:
packages/toolkit/dist/ofh-design-system-toolkit.css - JavaScript:
packages/toolkit/dist/ofh-design-system-toolkit.js - Minified versions:
*.min.css,*.min.js
Use case: Traditional websites, static sites, simple projects that want plug-and-play assets.
Individual component source files for modern build tools:
- SCSS:
packages/toolkit/components/**/*.scss,packages/toolkit/core/**/*.scss - JavaScript modules:
packages/toolkit/components/**/*.js
Use case: Modern applications using bundlers (webpack, vite, rollup) that want tree-shaking, selective imports, or customization.
Server-side rendering templates for generating HTML:
- Macros:
packages/toolkit/components/**/macro.njk - Templates:
packages/toolkit/components/**/template.njk
Use case: Server-rendered applications using Nunjucks/Eleventy for HTML generation.
Before v3.4.3 (single package):
- Single
package.jsonat root with version - One version number for everything:
v3.4.3,v3.4.2, etc. - Tag format:
v*(e.g.,v3.4.3)
After v4.0.0 (monorepo):
- Each package has its own
package.jsonwith independent versioning- Toolkit:
4.0.0,4.0.1,4.1.0... - React Components:
0.0.1,0.0.2,0.1.0...
- Toolkit:
- Git installations must specify subdirectory:
:packages/toolkitor:packages/react-components - Packages can be released independently
- Tag format:
- Toolkit:
toolkit-v*(e.g.,toolkit-v4.0.0) - React:
react-v*(e.g.,react-v0.2.0)
- Toolkit:
Each package in the monorepo can be installed independently:
Toolkit (styles, components, templates):
{
"dependencies": {
"@ourfuturehealth/toolkit": "github:ourfuturehealth/design-system-toolkit#toolkit-v4.5.0:packages/toolkit"
}
}React Components:
{
"dependencies": {
"@ourfuturehealth/react-components": "github:ourfuturehealth/design-system-toolkit#react-v0.4.0:packages/react-components"
}
}For Toolkit Maintainers:
- Separation of concerns: Toolkit, site, and React components are independent
- Independent versioning: Each package can be versioned separately
- Isolated dependencies: Each package has only the dependencies it needs
- Better tooling: Can run tasks per-package or across workspace
- Selective consumption: External projects can install just what they need
For Consumers:
- Cleaner imports: No need to know internal directory structure
- Standard npm package: Toolkit can be consumed like any npm package
- Flexible consumption: Use compiled assets, source files, or templates as needed
- Better IDE support: Standard package structure improves autocomplete and imports
- Selective installation: Install only the packages you need
Error: Template render error: (unknown path) [Line X, Column Y] Error: template not found: button/macro.njk
Solution: Ensure your template engine is configured with the correct search paths pointing to node_modules/@ourfuturehealth/toolkit/components/ or the appropriate relative path.
Error: Error: Can't find stylesheet to import.
Solution: Add --load-path ./node_modules/@ourfuturehealth/toolkit to your Sass compilation command, or configure your bundler's resolve paths.
Error: CSS/JS files not found in built site
Solution: Update your build configuration's passthrough copy or static file handling to point to node_modules/@ourfuturehealth/toolkit/dist/ (or packages/toolkit/dist/ within the monorepo).
// eleventy.config.js
const nunjucks = require('nunjucks');
module.exports = function configuration(eleventyConfig) {
// Configure Nunjucks to find toolkit templates
const nunjucksEnv = nunjucks.configure(
[
'views/',
'views/_includes/',
'node_modules/@ourfuturehealth/toolkit/components/',
'node_modules/@ourfuturehealth/toolkit/',
],
{
watch: false,
noCache: true,
}
);
eleventyConfig.setLibrary('njk', nunjucksEnv);
// Copy toolkit compiled assets
eleventyConfig.addPassthroughCopy({
'node_modules/@ourfuturehealth/toolkit/dist': 'ofh-design-system-toolkit',
});
// Copy toolkit asset files (icons, images, etc.)
eleventyConfig.addPassthroughCopy({
'node_modules/@ourfuturehealth/toolkit/assets': 'ofh-design-system-toolkit/assets',
});
return {
dir: {
input: 'views/',
output: 'dist/',
},
};
};{
"name": "your-site",
"scripts": {
"build:css": "sass --style compressed --load-path ./node_modules/@ourfuturehealth/toolkit ./styles/:./dist/css/",
"build:eleventy": "eleventy",
"build": "npm run build:css && npm run build:eleventy",
"watch:css": "sass --watch --load-path ./node_modules/@ourfuturehealth/toolkit ./styles/:./dist/css/",
"watch:eleventy": "eleventy --serve",
"dev": "concurrently 'npm:watch:css' 'npm:watch:eleventy'"
},
"dependencies": {
"@ourfuturehealth/toolkit": "github:ourfuturehealth/design-system-toolkit#toolkit-v4.0.0:packages/toolkit",
"@11ty/eleventy": "^2.0.0",
"nunjucks": "^3.2.4",
"sass": "^1.60.0"
},
"devDependencies": {
"concurrently": "^8.0.0"
}
}If you encounter issues during migration:
- Check that all paths are updated consistently
- Verify your template engine configuration
- Ensure toolkit is properly installed in
node_modules - Review the toolkit documentation site for component usage examples
- Open an issue on the GitHub repository