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 SchemaDemo BrandWhat it names
@design-schema@demo

Package scope

--ds---demo-

CSS custom-property prefix

AlertCallout

Component

ButtonCtaButton

Component

DisclosureExpander

Component

Button.variantemphasis

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 SchemaDemo BrandKind of identifierOccurrences
ButtonCtaButton

component name

35

variantemphasis

prop name

35

AlertCallout

component name

34

DisclosureExpander

component name

34

ds-textdemo-text

class or custom-element name

31

ds-buttondemo-cta-button

class or custom-element name

26

ds-stackdemo-stack

class or custom-element name

25

ds-icondemo-icon

class or custom-element name

14

--ds-icon-size--demo-icon-size

CSS custom-property prefix

12

ds-disclosure__triggerdemo-expander__trigger

class or custom-element name

12

ds-disclosuredemo-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.