Veriforce

1.17K · Design token downloads

Vantage, a Design System for Designers, PMs, and AI

Veriforce runs five products on five design libraries, and 10 designers couldn't keep pace with ~30 PMs. As the system's only designer and engineer, I built Vantage for designers and non-designers alike. Designers get one shared library, and PMs, developers, and their AI tools get our components and patterns built in: the look is locked in code, and written guidelines cover the behavior. About 4 micro-frontends run on it so far, and retiring the old libraries is next.

0
Micro-frontends on Vantage
0
Design token package downloads
0
Design variables vs. the last shared library (10K+ → 1.2K)

Role

Sole designer and engineer. Owned tokens, components, guidelines, and rollout.

Team

10 designers giving feedback. ~30 PMs and their dev teams building on it.

Timeline

Oct 2025 to today. Retiring the five legacy libraries is next.


The problem: five libraries, and more builders than designers

Veriforce sells contractor safety and compliance software. Acquisitions turned it into a suite of SaaS applications: Highwire, SafeContractor, Compliance Pro, Verisource, and WorkerPass. These frequent acquisitions had designers spread thin trying to maintain five different design libraries.

  • Customers felt the seams. A customer adding a second product got an app that looked and worked nothing like the first.
  • Design couldn't keep up. 10 designers served ~30 PMs with no shared components. Design either started from screenshots or utilized very outdated libraries.
  • The last shared system didn't stick. An earlier attempt was a Figma file of 10,000+ variables and all-custom components. It was too ambitious for a team our size, and the number of variables made it hard to adopt. Developers wanted something that was actively maintained.

The insight: designers needed one shared system, but most screens wouldn't be built by designers. They'd be built by PMs and developers, more and more through AI tools. Designers couldn't review all of those screens, so I wanted the system to carry as many of design's decisions and patterns as possible.

Most screens wouldn't be built by designers. They'd be built by PMs and developers, more and more through AI.

The bet: a theme on MUI, the library AI already knows

Aligning the old libraries would have kept five things to maintain. Going custom again would repeat the last attempt, and was too much for one person. So I built a theme on MUI. AI tools write React well, and MUI is the most popular React component library, already used in some of our apps. A model already knows it, so it builds with Vantage easily. MUI brings proven, accessible components, so I could spend my time on the parts that make them ours. It's the same call I made at Highwire with PrimeNG: pick a system the team can actually support.


How it fits together: one source, published for every stack

Vantage has three parts: tokens, components, and guidelines. They come from one source and ship together, so designers, developers, and AI tools all work from the same thing.

  1. 01
    Figma
    Source of truth
    Variables
    Primitives, theme, and component sizes
    Component library
    References the variables
  2. Tokens Studio exports the variables as JSON
    02
    Code repo
    Build
    Style Dictionary
    CSS · SCSS · JS/TS
    MUI theme
    MUI 7 · MUI 9
    Custom components
    React
    Guidelines
    Markdown
  3. 03
    npm
    Publish
    Tokens package
    Tokens, themes, and guidelines
    Components package
    Custom components
  4. 04
    Used by
    People and AI
    Angular apps
    CSS and SCSS tokens
    React apps
    Theme and components
    Figma Make
    Both packages and the guidelines
    Claude Design
    Synced from the repo by a GitHub workflow
    AI coding assistants
    The guidelines

Figma variables are the source. Everything after them is built and published from one repo.

I set it up this way so a token only has to change in one place. Designers work in Figma, so I made Figma variables the source of truth. That way designers can reference the same tokens developers use. From there, the build turns them into whatever each app needs, since our apps run on different stacks and MUI versions.

Publishing everything from one repo means apps, Figma Make, Claude Design, and AI coding assistants all pick up the same updates.

Once PMs and designers started building in Figma Make and Claude Design, we noticed AI would fill in gaps with its own choices, and it was producing screens faster than design could review them. So I split the system by what each part can enforce:

  • The look lives in the theme. Color, type, spacing, and component styling are set in code, so a model gets them right by default.
  • The guidelines cover behavior: how we handle errors, how tables work, and how components combine.
Anything that can be decided in code is locked in code. Words cover what code can't decide.

1. Tokens: small enough for one person to keep

The last shared system had 10,000+ variables, which made it hard for teams to adopt. By relying on a semantic layer of tokens and switching dark mode at the primitive layer, I got that down to about 1,200.

LayerWhat it holdsExample
PrimitivesRaw color scales, ten steps eachblue/600
ThemeWhat a color is for: surfaces, text, borders, stateserror/border
ComponentOnly sizes: border widths and radiibutton/border-radius

Component tokens only hold sizes, like border widths and radii. Component colors come from the theme layer, where each state, like error or success, gets the same set of slots. Teams pick from colors that already exist.

Brands only override two things: primary color and logo. For now, that means a brand can't restyle a single component. I was fine with that, since consistency across products was the goal.

Light and dark mode live at the primitive layer. That gave me room for exceptions: when a color needs to behave differently, like a primary button that should look the same in both modes, its semantic token just points at a different primitive. Otherwise the semantic layer would fill up with one-off tokens for each mode.

I tuned every color in both modes with contrast checkers in Figma and Lighthouse. I adjusted values until each scale had even steps, and checked the text and background pairs we use against WCAG AA.

/
50
100
200
300
400
500
600
700
800
900
gray
ink
blue
red
orange
amber
emerald
green
purple
pink
• 600 is the same value in both modes.
105 × 2
Primitive colors, each with a light and a dark value. The only layer that knows the mode.
360 × 1
Theme tokens, every component color included. Each is one reference to a primitive.

Drag to compare. Only the primitives change between modes.

The dark scales also aren't a straight inversion of the light ones. Flipped as-is, the darkest steps were too saturated for dark backgrounds and the lightest steps were too bright, so I muted the dark end and toned down the light end.

50
100
200
300
400
500
600
700
800
900
ink
Straight flip
Tuned
blue
Straight flip
Tuned
red
Straight flip
Tuned

Each dark scale is tuned for dark backgrounds, with softer ends than a straight flip would give.


2. Components: only the options we use

I found MUI was too flexible for us and offered more options than we needed. As a small team, I needed to keep the system narrow and focused, so I removed any unnecessary variants, like extra Checkbox and Radio sizes, extra TextField styles, and filled Alerts. I based most of these cuts on design systems from larger companies. My reasoning was that if very large companies can make it work with less variance, we could too. That keeps screens consistent, and cut down on maintenance.

Teams do lose some flexibility. If a team needs a variant I removed, we talk it through and decide whether to bring it back.

Custom components, where MUI stopped

MUI components didn't get us all the way there, so I maintain a thin layer of custom components on top of it. These came out of designing in Figma. They were the first gaps we noticed, where we wanted more control over the UX. Most of them, like the Sidebar and PageHeader, are mainly layout, so every app gets the same structure.

Table page
/
Contractor Management
JT
Jim Thompson
A & A Windows Incorporated
Projects
Add project
OverviewTasksFiles
AllSearch by name…
StatusType
ProjectTypeStatusProject managerLast updated
Riverside Office Complex
0012
CommercialActiveSCSarah ChenJun 1, 2026
Highway 9 Bridge Repair
0046
InfrastructureOverdueMIMarcus IanuciMay 28, 2026
Oakwood Residential Phase 2
0083
ResidentialOn holdJMJordan MillsJun 1, 2026
Westfield Warehouse Fit-Out
0061
CommercialCompletedTOTom OkekeMay 25, 2025
1–25 of 248
25 rows
Sidebar, PageHeader, TableToolbar, FilterChip, and TableCells. Every color comes from a theme token.

A table page built from the custom components. Every color on it is a theme token, so it switches modes with no dark values of its own.

FilterChip is different, because the behavior is the point. Every app filters tables, and without a shared component each team would build filtering its own way. FilterChip is one component with eight variants, from a yes/no toggle to number ranges. The select variants are built on MUI's Autocomplete and styled as a chip: you click to open it, type to narrow the list, and press Enter to pick. Multi-select stays open so you can pick several, and the chip resizes to show what's selected, with an X to clear it.

Writing all of that as guidelines would take pages, and teams would still build it a little differently. Putting it in the component means every app gets the same behavior.

FilterChip on the docs site. Type to filter and press Enter to pick. Multi-select stays open, single select closes on pick, and each chip resizes to fit its value.
Button variants from the design system docs in light mode and dark mode, side by side

Primary holds across modes. Error brightens and Secondary inverts. Every label's color comes from a token.


3. Guidelines: the judgment calls code can't make

Tokens and components only go so far. How a screen turns out still depends on how someone uses them, and that's the gap the guidelines fill. They put the reasoning behind our decisions in one place, written so designers and AI tools can both read it.

The guidelines are 28 Markdown files, mostly in three groups:

  • Components: when to use each one, with do's and don'ts. For example, use Radio for two or three options and Autocomplete for 15 or more.
  • Patterns: how components work together for common tasks, like adding, editing, and filtering table data, or validating a form.
  • Conventions: general rules that apply everywhere, like button hierarchy, required fields, and where focus goes.

When AI gets something wrong, I add a rule, so the guidelines keep growing with how people actually build. They're also published on the docs site, so designers read the same rules the AI does.

Example: editing a record. The Edit table data pattern says quick edits open in a drawer, so the table stays visible while you edit, and bigger edits get their own page. Having two ways to edit means people need to know which one to use, so the pattern spells it out: a handful of simple fields is a quick edit.

The Edit table data pattern page: four steps from row menu to drawer to save, above a live demo table

Each pattern pairs steps with a working demo, so people and AI get the decision along with the component.

Putting it together

Here's what tokens, components, and guidelines look like working together. The screen uses our tokens and components, and the layout follows our patterns.

One prompt in Figma Make, written the way a PM would ask it, with no design direction. The agent explains its own choice: “The drawer opens from the right with the table still visible behind it, which is what your design system's guidelines recommend for viewing a record.”

The prompt doesn't mention a drawer. The agent chose one based on the guideline and explained why.


Rolling it out: no mandate, and nothing retired yet

The goal is five libraries down to one. None is retired yet. That's the next phase, working with each product group.

The blocker is foundations. Several apps run old versions of Node and React, so they need to upgrade before they can take the full system. At each step, we weigh whether it's worth it for that app.

Design system adoption pathNew apps start on the full theme. Apps being replaced are not migrated. Apps not on React adopt the tokens only. Apps on older React upgrade Node and React, then MUI, and end on the full theme.Any Veriforce appNew app?NoYesStart on the full themeBeing replaced or merged?NoYesDon't migrate itBuilt on React?YesNoAdopt the tokens onlyOr move to React, if worth itOn React 17 or newer?YesNoUpgrade Node and ReactOn the latest MUI?YesNoAdopt or upgrade MUIFull theme

Each branch weighs the cost of moving. Apps that are being replaced skip it, and apps outside React adopt the tokens only.

We also follow two rules: don't hold up features sales needs, and don't migrate an app that's about to be replaced.

Legacy screens are the hardest call. If we design them in Vantage, developers can't build them 1:1 yet, but designing them in the old system doesn't move us forward. For now, new work goes first, and legacy screens follow where it makes sense.

An Employee Management prototype built on Vantage: a workforce overview, then one worker's record. Demo data.

PMs and designers both prototype in Figma Make on Vantage. It doesn't replace design review, and requirements are still an open problem. It does give us a better starting point, since a first draft already uses our components and patterns before a designer sees it.

It also helps set the vision. Day to day, it's easy for designers and PMs to stick with what we have, because it works. Prototyping on Vantage shows what our apps could look like and how they should behave, which gives teams something concrete to move toward as we migrate.

Feedback, and what I missed

I set up a feedback channel in Microsoft Teams so I could work with product teams directly and keep conversations in a public space, where everyone can see the questions and answers.

The biggest thing I missed was other languages. I built the components for English, and as regional teams picked them up, the first thing they asked for was translation. I added locale support, with eight languages so far, from French Canadian to German. Next time, I'd build it in from the start.

Where adoption stands

WhereStatus
Micro-frontendsAbout 4 on Vantage
Design tokens1.17K package downloads
ComponentsJust shipped, no numbers yet
Guidelines28 files, about 274 rules, ~49 components synced to Claude Design
Legacy libraries0 of 5 retired. Next phase.

Takeaways

  • Put the look in code, and use guidelines for behavior. AI tools follow defaults more reliably than written instructions, so I put as much as I could into the theme.
  • Remove the options you don't need. Fewer variants meant fewer inconsistencies, whether a person or AI was building.
  • Plan for other languages early. Adding translation to shipped components took more work than building it in would have.
  • Design for whoever is building the screen. Here that's often PMs using AI tools, so the system needs to carry design's decisions when a designer isn't involved.