One number for design system adoption.

Reach scans a React repo and answers one question: of all the UI you rendered, how much came from your design system?

View on GitHub
free and open sourcev1.0.0, released 2026-07-07
~/your-app
$ npx @usepolder/reach --library "@acme/ds" Polder Reach Score: 68.4% (412 DS / 602 countable instances) DS components 412 Other components 134 Styled host elements 56 Leaks: 87 (61 hex colors, 26 px values) Top offenders: src/styles/legacy.css (34)

How the Reach score is counted.

One formula, no settings

Reach counts every JSX opening element in the repo. You can make CI fail below a minimum score, but how things are counted never changes, so scores stay comparable between teams.

DS instances
DS + other components + styled host elements
DS instance. A capitalized JSX element that resolves to a package in component_library, including subpath imports like @acme/ds/Button and member expressions like <Table.Row>.
Other component. A capitalized element that resolves anywhere else: local components and other libraries.
Styled host element. A lowercase element such as div or span with a className or style. It counts against you, because it is UI that bypassed the system.
Excluded. Fragments and unstyled host elements, which are layout glue.

Run it on a repo.

npx @usepolder/reach --library "@acme/ds"Zero config beyond your design system package name. Add --json for the full machine-readable report.

Reach also reads the .polder.yml that Drift uses.

In pull requests and on the README.

GitHub Action

One pull request comment, updated on every push, with the score, the change against the base branch, and the leak count. It also sets score, base-score and leaks outputs.

- uses: actions/checkout@v4
- uses: usepolder/reach@v1

The job needs pull-requests: write to post the comment. If the base commit cannot be fetched, such as on fork pull requests, the comment shows the score only.

Config and badge

Set reach.fail_under to fail CI below a score. It gates the build and never changes the number. On every push to the default branch the action can commit a README badge, with no hosted service.

component_library: "@acme/design-system"
reach:
  include: ["src/**"]
  exclude: ["**/*.test.*", "**/*.stories.*"]
  fail_under: 0

Questions

What does the Reach score measure?

The share of countable UI that comes from your design system: DS instances divided by DS instances plus other component instances plus styled host elements, counted per JSX opening element across the repo.

Can I change how Reach calculates the score?

No. A score you can tune is a score nobody trusts. You can set reach.fail_under to fail CI below a minimum score, which never changes the number.

Which languages and design systems work?

Reach reads React code (JSX and TSX) and works with any design system that you name by its package, including in-house ones.

Does it send my code anywhere?

No. Reach runs on your machine or in your CI, with no server and no account.

Does it support monorepos and Azure DevOps?

Not yet. Per-package scores for monorepos and an Azure DevOps task are on the roadmap. Reach scores the whole repo today.

Can I add a Reach badge to a private repo?

Yes. Public repos use a shields.io endpoint file that the action commits. Private repos use a committed static SVG, because shields.io cannot read private raw files.

What does it cost?

Nothing. Reach is open source under Apache-2.0.

Part of Polder. See also Polder Drift. Latest release: v1.0.0, 2026-07-07.

Find your leaks.

npx @usepolder/reach --library "@acme/ds"
npx @usepolder/drift scan --all
Photos via Wikimedia Commons, cropped and compressed: header De Biesbosch-polder by Paul van de Velde (CC BY 2.0); footer Foto uit de lucht Spijkenisse by Peter van der Sluijs (CC BY-SA 4.0).