River
Y CombinatorBacked by Y Combinator
FREE TEMPLATE

Design System Documentation Template

A documentation site lists what the system contains. This register puts four usage counts on every component, so the ignored half shows up.

Free download  ·  No account needed

A design system documentation site answers what the library contains. It cannot answer the question a design system lead is actually asked, which is which parts of it anybody uses, because the library only sees its own side. Figma exposes library analytics through its API, so that side has been measurable for years. Join it to the front-end repository and the split appears at once: sixty-four components documented, forty-one imported at least once, twenty-three never imported in the codebase.

The twenty-three split again, and this is where the work is. Nine of them have a local re-implementation somewhere in the code, which means the need is real and the library component lost. Fourteen have no local equivalent at all, so nobody needs them. Those two groups need opposite decisions and an adoption percentage gives both the same score. Then nine components with no library entry carry five hundred and eleven call sites between them, which is the design system whether anyone approved it or not.

Tokens get the same treatment: three hundred and twelve defined, one hundred and eighteen never referenced once, fifty-seven with a literal in the code that exactly matches the token's own value. Grouping fixes by the component that causes them is the move the accessibility remediation pack makes on an audit export, the gap list feeds the roadmap pack, and reading components back out of an unfamiliar repository is inherited codebase documentation. A component missing an error variant produces the same gap on every screen using it, which is what the handoff register counts.

The library, joined to the code that was supposed to use it

Component Register, Token Map and the Gap List both of them produce.

Component Register

Illustrative rows for a fictional insurance operations platform, Kestrelane, whose design system is called Plume. Sixty-four published components joined to the front-end repository.

ComponentDoc'dLibraryImportsForksFilesVerdictWhat the fork adds
ButtonYes4,1803,41200Adopted-
ModalYes41038800AdoptedNobody rebuilds a working focus trap
DataTableYes19012734ForkedColumn resize, in all seven
TabsYes2106139ForkedActive tab in the URL
FileUploadBeta613514ForkedMore than one file
PaginationYes8819411ForkedCursor paging, which the API uses
DatePickerYes960411IgnoredFiscal quarters, in none of them
BreadcrumbYes74012IgnoredReads the router, not props
StepperYes34000UnusedNo fork anywhere. Nobody needs it
CarouselDeprecated12000UnusedDeprecated in 2024, still published
ToastNo0214-31UndocumentedThis is the notification system
CurrencyInputNo096-22UndocumentedNegative premiums, four currencies
EmptyStateNo047-19UndocumentedThree visual variants, no owner

Sixty-four documented components: adopted 32, forked 9, ignored 9, unused 14. Nine more live only in code and carry 511 call sites between them, more than the bottom forty library components combined.

Token Map

Three hundred and twelve tokens across light, dark and high contrast. The last column counts literal values in the code that exactly equal the token's own.

TokenLightDarkContrastRefsBypassesVerdict
color.text.primary#1B2430#E8EDF2#FFFFFF1,9040Healthy
radius.control6px6px0px7808Healthy
font.size.body15px15px15px41238Bypassed
color.border.subtle#E2E6EB#26313D#FFFFFF34114Bypassed
color.chart.grid#EDF0F3#1D2731#FFFFFF427Bypassed
space.gutter.page32px32px32px061Bypassed
color.status.warning#B54708missing#FFFF00962Incomplete
color.chart.series-01#2E5AACmissing#0000FF410Incomplete
color.overlay.scrim48% scrim64% scrimfully opaque880Incomplete
elevation.overlaydefineddefinednone00Unused

Three bypass patterns, three different fixes. space.gutter.page has zero references and sixty-one literal 32px gutters, which is nobody knowing it existed and one codemod. font.size.body has 412 references and a tail of 38, which is a lint rule. color.chart.grid loses to a charting API that takes hex strings, and no amount of discipline fixes that.

Gap List

Sorted by independent fork count, because seven teams building the same thing is seven teams saying the same thing.

GapKindEvidenceDecisionEffort
DataTable column resizeLibrary gap7 forks / 34 filesAdd resize, migrate all seven3 weeks
FileUpload multi-fileLibrary gap5 forks / 14 filesPromote the beta before a sixth appears2 weeks
Pagination cursor modeLibrary gap4 forks / 11 filesOffset-only was the wrong default1 week
Tabs URL syncLibrary gap3 forks / 9 filesControlled mode; forks collapse to a prop4 days
ToastUndocumented214 imports / 31 filesAdopt as-is. The API does not change1 week
CurrencyInputUndocumented96 imports / 22 filesAdopt. No primitive covers it1 week
EmptyStateUndocumented47 imports / 19 filesConsolidate three variants to one4 days
DatePicker fiscal quartersIgnored0 imports in 18 monthsRewrite or retire. Zero is a verdict2 weeks
Breadcrumb router integrationIgnored0 imports / 1 forkReplace ours with the fork1 day
Stepper, Carousel, SplitButtonUnused0 imports / 0 forksRetire as one batch1 hour
Warning colour, dark modeIncomplete token96 call sites, no dark valueFails contrast today. Goes first1 hour
space.gutter.page literalsToken bypass0 refs / 61 literalsCodemod. The token was always right1 day

The bottom four rows total under two days and close a conformance failure, twenty-three components' worth of dead library surface, and sixty-one literal gutters. The top row is three weeks and the one everybody argues about.

What is in the pack

01

Component Register

One row per component with four counts rather than one percentage: library instances, code imports, separate local re-implementations, and the files those live in. The verdict is derived from how the four relate.

02

The undocumented block

Components with real call sites and no library entry, counted the same way. In the worked example nine of them carry 511 imports, which is more usage than the bottom forty library components put together.

03

Gap List

Every open decision, sorted by independent fork count, with what each fork adds, who owns the fix, and an effort estimate. This is the sheet you take into a planning conversation.

04

Token Map

Value per mode, reference count, and the count of literal values in the code that exactly equal the token's own. Tokens with zero references and dozens of literals are ones nobody knew existed.

05

Component Guidance

Usage, when to reach for something else, the anti-pattern, and what a breaking change costs in call sites. Written in register order, so a component nothing imports says so instead of appearing available.

06

Contribution Process

Four routes keyed to what the register already knows, because most requests have already been made by somebody who built the thing. Only the genuinely new component gets a form, and it is three questions.

How it works

  1. 1

    Send both sides

    The published library or a token export, plus read access to the front-end repository. Either side alone still produces real findings.

  2. 2

    Join them

    Every component gets its library instances, its call sites, and the local re-implementations competing with it, matched across naming differences.

  3. 3

    Read the forks

    Each fork records what it does that your component does not. Where several forks add the same capability, that is one missing feature with several witnesses.

  4. 4

    Decide from the Gap List

    Adopt, extend, rewrite or retire, sorted by fork count, with the call-site cost of every change attached.

Frequently asked questions

What do I need to give it?

The published library or a token export, and read access to the front-end repository. Figma, Sketch, a Storybook build, a token JSON file, or a documentation site export all work. One side alone still finds every token nobody references and every mode with a missing value.

How does it find a local component that duplicates one of ours?

By shape first, then by reading it. Components with the same props, the same rendered element or the same interaction get grouped, then each candidate is read to confirm it does the same job. A feature-folder table and your DataTable can look alike and be genuinely different.

Why not just report an adoption percentage?

Because it recommends nothing. A component with zero imports and four local forks needs rewriting; a component with zero imports and no fork anywhere needs deleting. Both score zero percent. The four verdicts exist because those are four different pieces of work, and one number hides which.

Isn't a local fork just someone ignoring the design system?

It is a feature request with a working implementation attached, written by an engineer who spent a day on it rather than filing a ticket. Seven independent forks all adding column resize is not seven discipline problems. It is one missing feature with seven witnesses, and it tops the Gap List.

Does it handle tokens as well as components?

Yes, and the same way. Value per mode against the Design Tokens Format Module, reference count, and literal values in the code matching a token exactly. It also flags any token whose missing mode value breaks something, which is how the prioritization pack gets a ranked list.

What about accessibility problems in the system itself?

The register surfaces them where a token causes one. A warning colour with no dark value leaves 96 call sites inheriting a light colour that misses the 4.5 to 1 floor for normal text. For a full audit export, the accessibility remediation pack does the same regrouping on findings.

Our system is nine components and a colour file. Worth it?

Yes, and it takes an afternoon. Small systems have the same problem in sharper form: two of nine components unused is a fifth of the library, and the undocumented list is usually longer than the documented one. It also gives you a contribution process before the first argument about one.

Find out how much of your system is dead

Send the library and the repository. The first number back is how many documented components your product has never imported once.

Count my components