Design systems

How 10 Public Design Systems Are Built, Compared From Their Repos

We read ten public design-system repositories instead of their landing pages. Token formats, package layouts and theming mechanisms differ more than the marketing suggests.

· · Diagram Studio Editorial

Ask five teams how many components their design system has and you will get five numbers, none of them comparable. The same goes for tokens: every system claims layers, and the layers carry different names. Landing pages make all ten look alike. The repositories do not.

We read ten public design-system repositories on one day, October 1, 2026, using shallow clones and three small scripts, and wrote down where each keeps its token values, how its themes reach the page, how its packages are cut and how its components can be counted fairly.

If you are choosing or auditing a design system, this comparison is for you. After reading, you should be able to tell what adopting each one entails and to run the same five checks on any system you are considering.

Direct answer

In ten public design-system repositories snapshotted on October 1, 2026, no two share a token pipeline. Token values are written as JSON (2 systems), TypeScript (5), CSS or Sass (2), or kept in a separate repository (1). Repository shape runs from one package to 249 workspace packages, and component counts depend so much on the counting rule that one "number of components" does not compare.

Ten systems, ten token pipelines

No two of the ten repositories build design tokens the same way, and the headline numbers hide most of what matters. Four findings came out of the files.

  • Token values live in four kinds of place. JSON or JSON5 (Primer, Carbon), TypeScript (Fluent, Chakra, Mantine, Ant Design, shadcn/ui), CSS or Sass (Radix Themes, Material Web), or a separate repository (React Spectrum).
  • Themes reach the page in three ways: shipped CSS, a runtime JavaScript theme, or a build-time macro. Which one a system uses decides whether you can change a theme at runtime.
  • Package and component counts only compare under a written rule. Repository shape runs from one package (Ant Design) to 259 workspace packages (Fluent), and Carbon's React package alone gives 147 component folders against 100 for its web-components package.
  • Status matters more than size. One system is in maintenance mode, one reference system is archived, and one ships code you copy instead of install.

A design token is a named design value, such as a colour, a spacing step or a duration, stored once so design tools and code read the same source. Jina Anne, who helped popularise the idea, described its origin this way:

this was a way to store our visual information as data and then, in an automated way, generate the variables or the XML data you needed or the JSON data

Jina Anne, Design tokens pioneer, Smashing Podcast guest — Smashing Podcast Episode 3 With Jina Anne: What Are Design Tokens?

The Design Tokens Community Group published the first stable version of a shared token format, 2025.10, in October 2025. Two of the ten systems write tokens in that format's key style. The other eight do not.

What was cloned, and the counting rules

The ten systems are IBM Carbon, GitHub Primer, Material Web, Adobe React Spectrum, Fluent UI, Chakra UI, Mantine, Radix Themes, shadcn/ui and Ant Design. They solve different problems: a copy-and-own registry, a web-components library, an enterprise kit and a React toolkit are not competing for the same job. Shopify Polaris React was measured under the same rules but is archived, so it is a reference row.

Primer is the only system whose components and tokens sit in two repositories, so both are listed. The scripts and raw output are saved in the article's evidence folder, and the rules in each section are enough to reproduce the counts.

Snapshot of each repository: commit, date and license file as read on October 1, 2026
SystemRepository at commitLast commitLicense fileNote
Carboncarbon-design-system/carbon @ c73d2272026-10-01Apache-2.0Active
Primer (components)primer/react @ c4189aa2026-09-30MITTokens are in primer/primitives
Primer (tokens)primer/primitives @ f48bc062026-09-09MITToken source and build
Material Webmaterial-components/material-web @ a6b2d262026-09-30Apache-2.0README says maintenance mode
React Spectrumadobe/react-spectrum @ 57c56b82026-09-30Apache-2.0Includes Spectrum 2 package
Fluent UImicrosoft/fluentui @ 61167612026-10-01MITGitHub API reports no SPDX match; the file reads MIT
Chakra UIchakra-ui/chakra-ui @ 96116142026-09-24MITActive
Mantinemantinedev/mantine @ f38933c2026-09-26MITActive
Radix Themesradix-ui/themes @ 1faff102026-04-11MITLast commit about five and a half months old
shadcn/uishadcn-ui/ui @ b0fcb582026-09-30MITCopy-and-own registry
Ant Designant-design/ant-design @ 820e1a82026-10-01MITSingle package
Polaris React (reference)Shopify/polaris-react-archive @ 3f7954a2026-09-09MIT-style textArchived, deprecated

One caveat: the Primer React clone warns on case-insensitive file systems because some Playwright screenshots differ only by letter case. Those are image files and do not affect any count.

Where token values are written

Token values sit in four kinds of place, so adopting a system also means adopting its build pipeline. The table gives the location, the format and one count per system as evidence that the files exist. The counts are file counts or text matches, so do not compare them across rows: a JSON5 $value and a TypeScript var(--x) line are different units.

Where each system writes token values (counts are not comparable between rows)
SystemWhere token values are writtenFormatEvidence in the repo
Primerprimer/primitives, src/tokensJSON5 with $value and $type keys, compiled with Style Dictionary61 JSON5 files, 3,453 $value matches; Style Dictionary 5 as dev dependency
Carbonpackages/themes/src/dtcgJSON in the Design Tokens Community Group format; older TypeScript definitions remain6 JSON files with 312 $type nodes; 12 TypeScript token files still present
Fluent UIpackages/tokens/src (global, alias, themes)TypeScript11 + 8 + 8 files; 467 tokens mapped to var(--…) names
Chakra UIpackages/react/src/theme/tokens and semantic-tokensTypeScript18 token files, 3 semantic-token files; 107 _light value pairs in semantic colors
MantineMantineProvider/default-theme.ts and default-css-variables.cssTypeScript theme object plus a CSS file99 CSS Modules in @mantine/core
Ant Designcomponents/theme (seeds, maps, alias, algorithms)TypeScript5 map files; 3 algorithm folders (default, dark, compact)
shadcn/uiapps/v4/registry/themes.tsTypeScript objects holding cssVars for light and dark24 registry:theme entries; 809 oklch() values
Radix Themessrc/styles/tokensHand-written CSS custom properties10 token CSS files plus 31 colour-scale files
Material Webtokens/Sass2 reference, 6 system and 49 component token files
React SpectrumNot in this repo: @adobe/spectrum-tokens 14.15.0JSON, imported by the Spectrum 2 packageOne dependency; source in adobe/spectrum-design-data

For a closer look at how JSON and Markdown token files serve AI agents, see the comparison of Markdown and JSON design tokens for agents. For lint rules over the public files in the newer DESIGN.md format, see the DESIGN.md linter write-up.

Three details matter more than the counts. Carbon's README says all themes and component tokens "have been migrated" to the Community Group format, yet twelve older TypeScript token files are still in the tree, so the repository is mid-transition.

Watch 107. The Evolution of IBM's Carbon Design System with Scott Strubberg by Knapsack on YouTube
An interview about how IBM's Carbon has evolved, useful background for the token migration still visible in its repository (we did not watch it; the framing comes from the title).

Primer keeps tokens and components in different repositories, and its React package lists @primer/primitives as a dependency (10.x or 11.x). Radix Themes has colour-scale CSS in the repo but also depends on @radix-ui/colors, so the scales are partly sourced elsewhere.

Spectrum is the clearest case of tokens living outside the component repository. Its Spectrum 2 package takes @adobe/spectrum-tokens 14.15.0 as a development dependency. Adobe's styling documentation says the style macro runs at build time and returns a class name that applies Spectrum 2 design tokens, so token JSON is consumed when the app is built, not shipped as a theme object.

A couple years ago I designed the styling system for React Spectrum. It's inspired by StyleX and Vanilla Extract's Sprinkles, and built on bundler macros.

— Devon Govett (@devongovett) View on X
The designer of the styling system explains its lineage; the repo's Spectrum 2 `style` folder is where the macro approach lives.

Token layers: who names them

Layer names are local conventions, not a standard. A token layer is a step of indirection: a raw value, then a meaning that points at it, then optionally a component-specific name. Four systems expose layers in their file names or docs, with four vocabularies.

Hand-drawn chart with four rows showing token layer names: Material Web ref, sys, comp; Primer base, functional, component; Ant Design seed, map, alias; Fluent UI global, alias, themes.
Layer names come from folders and files in each repository, so they are local labels and not a shared standard.

Material Web's tokens/ folder holds 2 reference, 6 system and 49 component files, named _md-ref-*, _md-sys-* and _md-comp-*. Primer's token source splits into base (12 files), functional (22) and component (27), and its token documentation calls base tokens the lowest level. Ant Design's theme documentation names seed, map and alias tokens. Fluent's @fluentui/tokens has global, alias and themes folders with 11, 8 and 8 files.

Carbon and Chakra do not use the same triple. Carbon's DTCG folder separates theme tokens (one file covering four themes) from component tokens. Chakra separates base tokens, semantic tokens and recipes, which are component style definitions. Both are our reading of the folder structure.

The practical point is modest: three tiers is a common pattern, not a rule, and the names do not map one to one. What does match is the middle tier, the one that gives a value a meaning such as "surface" or "danger". That is where light and dark modes, high-contrast themes and brand overrides attach.

How a theme reaches the screen

The ten systems deliver themes in three ways, and the choice decides whether a theme can change at runtime, whether a provider component is required, and where theme values can go wrong.

Hand-drawn diagram with three lanes feeding a page: build time for Spectrum 2, runtime from a JS theme for Fluent UI, Chakra, Mantine and Ant Design, and shipped CSS for Carbon, Primer, Radix Themes, Material Web and shadcn.
Delivery model per system; the Carbon, Primer and Material Web placements are our reading of their build and style files.

Shipped CSS. The theme is a set of CSS custom properties in a stylesheet, switched by a class or attribute. Radix Themes writes .dark and .dark-theme selectors in all 31 of its colour files. Primer's React package reads data-color-mode in 5 files, and its token build defines 14 theme variants. Material Web's components reference --md-sys-color-* in 26 Sass files. shadcn/ui's theming guide describes CSS variables for semantic tokens such as background and primary.

Carbon's themes package emits custom properties for four themes: white, g10, g90 and g100. Putting Carbon, Primer and Material Web here is our reading; we did not trace every code path.

Runtime from a JavaScript theme. A provider turns a theme object into CSS variables when the app runs. Fluent's FluentProvider renders a <style> element with rules such as --colorNeutralForeground1: value. Mantine's provider injects a <style> element and sets data-mantine-color-scheme, which appears 16 times across 9 files in @mantine/core. Chakra mounts an Emotion <Global> and switches on a .dark class, with 107 _light and _dark pairs in its semantic colours. Ant Design registers styles through useStyleRegister and offers an optional cssVar mode.

Build time. Spectrum 2 is the only one of the ten that resolves tokens into atomic CSS during the build, through its style macro, with light-dark() expressions in its theme file. The trade-off, our reading, is that there is no theme object to inject at runtime, so arbitrary themes are harder to supply from application code.

Runtime generation makes the theme ordinary data, which suits per-tenant branding. Shipped CSS needs no provider and works with a plain stylesheet, but a new theme means new CSS. Neither is better in the abstract; they fit different products.

Repository shape: from one package to 259

Package counts say more about how code is cut up than about product size. We counted a workspace package as any directory matched by the workspace globs (negations honoured) that contains a package.json, plus a named, non-private root manifest. "Non-private" still includes internal tooling not marked private, such as Mantine's documentation packages, so read it as an upper bound on what is published.

Workspace shape at the pinned commits
SystemWorkspace tooling at the rootWorkspace packages (all / non-private)Framework targets declared in this repo
CarbonYarn, Lerna, Nx38 / 28React, web components (Lit); also an icons-vue package
Primer componentsnpm, Turborepo13 / 4React; a styled-react compatibility package
Primer tokensnpm3 / 2None (tokens only)
Material Webnpm, one library plus a catalog site2 / 2Web components (Lit)
React SpectrumYarn, Lerna249 / 220React (205 packages declare it)
Fluent UIYarn, Nx259 / 131React (97 packages), web components (2 packages)
Chakra UIpnpm20 / 6React; a Panda preset package
MantineYarn32 / 30React; optional Emotion and vanilla-extract packages
Radix Themespnpm, Turborepo2 / 1React
shadcn/uipnpm, Turborepo5 / 3React registry components plus a CLI package
Ant Designnone (single package)1 / 1React

The big numbers belong to systems that publish one package per component or concern. Fluent's React v9 components live in 60 separate react-* packages, and Spectrum splits state, accessibility hooks and styled components into separate families. That is our reading of the layout.

Framework reach is uneven too. Seven of the ten ship React only. Carbon, Fluent and Material Web include web components in the same repository. Other framework ports may exist in other repositories, which this study did not search.

Component counts and why they do not compare

One rule per source directory, applied the same way everywhere. For PascalCase layouts, count immediate subdirectories starting with a capital letter. For kebab-case layouts, count immediate subdirectories (or .tsx files where a component is a single file) not on a short deny list of helper folders such as utils, internal, hooks and theme. Material Web is counted as unique @customElement('md-…') tag names, because its folders group several elements. Fluent React counts react-* packages that contain a src/components folder.

Component units under the stated rules (folders, files or tags, not verified user-facing components)
SystemSource countedRuleUnits
Carbon@carbon/react componentsPascalCase folders147
Carbon@carbon/web-components componentskebab-case folders100
Primer@primer/react sourcePascalCase folders74
Material Web@material/webunique md-* element tags62
React Spectrum@react-spectrum/s2 sourcePascalCase .tsx files89
React SpectrumReact Aria Components sourcePascalCase .tsx files65
Fluent UIReact v9 component packagesreact-* with src/components60
Fluent UIWeb components v3folders with a same-named .ts42
Chakra UI@chakra-ui/react componentskebab-case folders115
Mantine@mantine/core componentsPascalCase folders116
Radix Themes@radix-ui/themes components.tsx files, minus .props59
shadcn/uiRegistry, Radix base.tsx files in ui61
shadcn/uiRegistry, Base UI base.tsx files in ui62
Ant Designantd componentskebab-case folders77
Polaris React (archived)@shopify/polaris componentsPascalCase folders121

Four things show why one number misleads. The same system gets two answers: Carbon's 147 against 100, Fluent's 60 against 42. Counts include parts that are not catalogue components: 6 of Carbon's 147 folders end in "Item", and Chakra's 115 include layout primitives such as box, flex and stack. Material Web counts md-filled-button and md-outlined-button as two elements. And shadcn/ui ships parallel registries whose ui folders differ by one file, toast.tsx, which exists only in the Base UI set.

If you need a comparable figure for your own shortlist, write the rule down first, count under it, and publish the rule beside the number.

Status and distribution change what you are adopting

Two systems here carry status notices that matter more than any count, and a third changes who owns the code. Nathan Curtis's line, quoted in Brad Frost's chapter on maintenance, explains why:

A system isn’t a project with an end, it’s the origin story of a living and evolving product that’ll serve other products.

Nathan Curtis, Design systems consultant, quoted by Brad Frost — Maintaining Design Systems | Atomic Design by Brad Frost

MWC is in maintenance mode pending new maintainers

Material Web maintainers, README of the material-components/material-web repository — GitHub - material-components/material-web

The notice sits in the README of a repository that had a commit on September 30, 2026. Maintenance mode is the maintainers' own description; we did not assess what it means for any release plan.

The Shopify Polaris React library is deprecated. We are no longer accepting contributions or feature requests in this repository.

Shopify, README of the Shopify/polaris-react-archive repository — GitHub - Shopify/polaris-react-archive

The same README says Polaris Web Components were released on October 1, 2025, so a search for "Polaris design system" can return a deprecated React library. Distribution is the other hidden variable. Most systems here are packages you install and upgrade. shadcn/ui is not:

This is not a component library. It is how you build your component library.

shadcn/ui documentation, Project documentation — shadcn/ui documentation

In practice the registry components are copied into your project and become your code, with the theme as CSS variables in your stylesheet. That changes upgrade work, ownership and review, and no package count captures it.

Radix Themes shows a third pattern: its last commit was April 11, 2026, much older than the rest of the sample. A quiet repository is not by itself evidence of abandonment, and we did not examine its issues or releases. Check both before relying on it for new features.

Read the repository, not the component count

Ten public design systems answer the same question, how to keep an interface consistent, with ten different pipelines. What affects a team is where token values are written, how a theme reaches the page, who owns the code after adoption, and whether the project is still moving. The same five checks work on any system, public or internal.

Hand-drawn five-step checklist: find the packages, find the token files, find the theme switch, count with a written rule, check license and last commit.
The five checks behind this comparison; each one maps to a table above.
  1. Find the packages. Read the root package.json workspaces or pnpm-workspace.yaml, list directories with a package.json, and note which are marked private.
  2. Find the token files. Search for $value, -- custom property declarations or a tokens folder, and note whether the source is in this repository or a dependency.
  3. Find the theme switch. Search for data- attributes and .dark selectors, and for providers that render a <style> element or call a CSS-in-JS registration function.
  4. Count with a written rule. Pick one source directory per package, define a unit, and keep the rule next to the number.
  5. Check license and last commit. Read the license file, run git log -1 --format=%cI, and look for archive or maintenance notices in the README.

Once you have those answers, draw them: a design-system diagram of packages, token tiers and the theme switch shows a team in one picture what the tables above spread across pages. The same files are also what an AI agent needs to follow a system's rules; the guide to Claude Design skills covers how that rule set is packaged, and the comparison of design-to-code mechanisms shows what each tool reads from a repository like these.

Everything above reflects October 1, 2026. The rules are meant to survive a re-run even when the numbers do not.