Naming: a worked example
An adopter can rename what the generator emits: the components, a prop here and there, the CSS custom-property prefix, the package scope. They do it in one file that sits beside their theme doc and never touches the canonical schema — which is also why an upstream pull comes through without a conflict. This page is that mechanism, run for real.
Everything in the right-hand column below was generated from the same component docs as the left-hand column, by the same generator, and then renamed as the last step before the files were written. The two columns are given the same props — under whatever name each build calls them — and nothing else about them differs.
25 generated files, 15 of them renamed, 663 names different from the canonical build — and every one of them an identifier.
The same components, twice
Button → CtaButton
Design Schema
import { Button } from '@design-schema/react'
0 presses
Demo Brand
import { CtaButton } from '@demo/react'
0 presses
Disclosure → Expander
Design Schema
import { Disclosure } from '@design-schema/react'
Demo Brand
import { Expander } from '@demo/react'
Alert → Callout
Design Schema
import { Alert } from '@design-schema/react'
Your session is about to expire
You will be signed out in five minutes unless you carry on working.
Demo Brand
import { Callout } from '@demo/react'
Your session is about to expire
You will be signed out in five minutes unless you carry on working.
What is the same
The markup. The two renders produce the same elements, nested the same way, with the same attributes. The gate for this page diffs them in the browser and fails on any difference that is not an identifier.
The accessibility tree. Same roles, same accessible names, same states — a screen reader cannot tell the two columns apart.
The test hooks. The renamed button still says data-ds="Button", because that is how the derived behavior and keyboard gates find a component, and a gate that had to know what a brand calls its button would not be brand-agnostic.
The tokens. A component’s own hooks take the brand prefix, but what they resolve to does not: both columns read var(--color-action-primary-background), because a token path is canonical schema rather than brand vocabulary.
The naming doc
This is the whole of it — three components, one prop and the namespace. Every key is the canonical name, which is what lets the resolver check the doc against the schema and fail loudly if an upstream rename ever leaves a key pointing at nothing.
themes/demo-brand/naming.md, in full
6 rows| Design Schema | Demo Brand | What it names |
|---|---|---|
| @design-schema | @demo | Package scope |
| --ds- | --demo- | CSS custom-property prefix |
| Alert | Callout | Component |
| Button | CtaButton | Component |
| Disclosure | Expander | Component |
| Button.variant | emphasis | Prop |
Every identifier that moved
Counted by diffing each renamed file against the canonical file it was generated from. The comparison is structural: the two files have to produce the same names in the same positions, separated by byte-identical text, and every name that differs has to be one the doc above accounts for. Nothing else in the tree is allowed to move.
Identifiers renamed across the demo tree
12 rows| Design Schema | Demo Brand | Kind of identifier | Occurrences |
|---|---|---|---|
| Button | CtaButton | component name | 35 |
| variant | emphasis | prop name | 35 |
| Alert | Callout | component name | 34 |
| Disclosure | Expander | component name | 34 |
| ds-text | demo-text | class or custom-element name | 31 |
| ds-button | demo-cta-button | class or custom-element name | 26 |
| ds-stack | demo-stack | class or custom-element name | 25 |
| ds-icon | demo-icon | class or custom-element name | 14 |
| --ds-icon-size | --demo-icon-size | CSS custom-property prefix | 12 |
| ds-disclosure__trigger | demo-expander__trigger | class or custom-element name | 12 |
| ds-disclosure | demo-expander | class or custom-element name | 10 |
| --ds-stack-gap | --demo-stack-gap | CSS custom-property prefix | 9 |
116 more, all of the same kinds — packages/react/demo-brand/DIFF.md lists every one.
One thing on this page is not what a real fork would have
Demo Brand’s components import @demo/tokens, because renaming the package scope is what its naming doc asks for. A real fork publishes a package by that name; this repository has one token package, so the demo tree aliases the specifier back to it in its tsconfig, its Vitest config and this site’s Astro config. The generator writes component files, never manifests — package names are the fork’s own edit, and that is the same in every adoption.