describe(me) docs
early v0.12.1 browser mode · jsdom Live · Foundations
Examples npm GitHub

Foundations

Foundations shows the tokens of the project's design system, read from what the tests load, without stories or MDX. This page covers where the tokens come from, what the view shows, how it shows each design system and how it shows the dark variant.

Where the tokens come from #

After every run, the reporter writes foundations.json next to the manifest. It reads four sources:

foundations is the option, and the output directory says how the file is stored. Only CSS that the tests load counts. A token stylesheet that only the app entry imports never reaches a frame, so its tokens are missing too.

When two sources name a token

A token shows once. This decides which source it shows from:

The view #

A Foundations entry sits in the sidebar of the viewer, above the test files. It shows when the run found tokens, as foundations in the manifest counts them, or when the project uses Material UI. It names the design systems, such as Tailwind · shadcn/ui, Material UI · Emotion or styled-components, and custom properties when there is none.

The view has one section per token group, in this order: Colors, Typography, Spacing, Radius, Shadows, Breakpoints, Motion and Other. Only the sections with tokens show, each as a button with its count.

The specimens of the shown section render in one iframe, sandboxed with allow-same-origin only, so no script runs, as in a frame. It loads the project's own token and font stylesheets inside @layer project, so fonts and var() are real. The view's own CSS sits outside any layer, so it wins where both set the same property.

Blocks

Inside a section, the tokens fall into blocks, such as Semantic colors, Type scale or Elevation. A preset per design system forms them, as Design systems describes. Each block has a title in readable words, the name prefix its tokens share, such as --chart-* or palette.primary.*, and its count. A note under the title says what the block leaves out or how to change it. Within a section, the blocks come in this order, and an empty block drops out:

  1. The tokens of the theme module.
  2. The custom properties of the recorded stylesheets: the blocks of a preset, then blocks by name prefix, then Custom properties for the rest.
  3. The tokens of the Tailwind theme, with Tailwind's default palette last.

A framework default carries a default badge next to its name, so the project's own tokens stand out. The defaults come from two sources: Tailwind's defaults, and the tokens of a Material UI theme module that equal Material UI's own, as Design systems describes. The compact grid of Tailwind's default colors carries one badge on its title instead.

Specimens

Section Specimen
Colors a swatch, a large chip in the ramp of a color family, a small chip in a compact palette with its name and value in the tooltip, or a pair tile: Aa in the foreground on the background, with their contrast
Typography a sample line in the family, the weight, the size with its line height, the line height or the letter spacing, in the whole style of a composite typography token, or in a font shorthand. A line height's sample wraps over at least two lines. The Tailwind theme's weights, tracking and leading paint their sample in the theme's sans font
Spacing a bar of that length. A spacing scale adds a row per multiple, with its length in pixels
Radius a box with that border radius
Shadows a card under a box or inset shadow, a shape under filter: drop-shadow(), or Aa under a text shadow
Breakpoints a bar each, scaled to the widest of its block
Motion and Other a list row each

Each token shows its raw value. When the value refers to other tokens and resolves to something else, it shows raw → resolved, such as var(--radius) → 0.625rem or calc(var(--radius) - 4px) → calc(0.625rem - 4px).

Filter

The field in the toolbar filters the tokens by name and value. Every word must occur, in any case, in a token's name or in its raw light or dark value. So brand finds --color-brand-500, and 0.7 0.18 285 finds the tokens whose name or values hold all three. A pair shows whole when either of its tokens matches, and a type style when the name of one of its custom properties does. While the field holds text, each section button counts its matches, and a section without one shows no token matches.

/ focuses the field while Foundations is open. Esc clears it and leaves the field. Enter leaves the field and, when the open section has no match, opens the first section with one. The filter is not part of the link. It starts empty each time Foundations opens and when a new run arrives.

The inspector

While Foundations is open, the inspector shows a foundations section. A row that does not apply is left out.

systems
The design systems with their versions. shadcn/ui adds its style and base color from components.json.
Tailwind entry
The CSS file that loads Tailwind, such as src/index.css.
theme module
The module and its export, such as src/theme.ts#theme, with its adapter.
stylesheets
How many token and font sheets, such as 1 token sheet, 1 font sheet.
dark variant
What dark applies: class .dark, attribute [data-theme="dark"], prefers-color-scheme, theme modes or none (the dark variant).
collected
How long the reporter took to collect the tokens, in milliseconds.

An errors section lists the problems the reporter met while collecting. foundationsErrors says what to do about them.

Links and hosting

The link keeps the section as foundations=<section>, which Links describes with the rest of the address. Foundations works on a static site from describe-me build and without Live. The viewer fetches foundations.json only when the view opens.

See the colors of the shadcn/ui example, its radius, where the project's own tokens show raw → resolved, and the typography of the Material UI example.

Design systems #

A preset per design system groups the tokens into blocks. Material UI goes first, then shadcn/ui and Tailwind, and a generic preset takes what is left. A token still shows once, in the section of its kind.

Tailwind

The tokens of the Tailwind 4 theme form these blocks:

Colors
A ramp of large chips per color family of the project with at least three numeric steps, such as --color-brand-*. Then Theme colors for the project's other colors, and Tailwind palette: the default colors in a compact grid, one row per family. Its note says how to remove it: add --color-*: initial to @theme.
Typography
Font families, Type scale with each size's line height, Font weights, Tracking, Leading and Base font.
Spacing
Spacing scale: --spacing, then a row per multiple that utilities such as p-4 use, from 1 to 96, each with its length in pixels.
Radius
Radius scale.
Shadows
Box shadows, Inset shadows, Drop shadows and Text shadows, each painted the way its utility paints it.
Breakpoints
Breakpoints and Containers.
Motion
Easing, Animations and Transitions.
Other
A block per namespace, such as Blur, Perspective and Aspect.

The project's tokens and Tailwind's defaults share a block, and each default carries the default badge. See the spacing scale and the typography of the shadcn/ui example.

shadcn/ui

With shadcn/ui, its custom properties form four blocks ahead of the Tailwind ones:

Semantic colors
The color custom properties outside the chart and the sidebar. --primary and --primary-foreground form a pair, as does every --X with its --X-foreground, and so do --background and --foreground. A pair shows as one tile: Aa in the foreground on the background, both tokens with their values, and their contrast. The singles, such as --border and --ring, follow as swatches.
Chart
--chart-*.
Sidebar
--sidebar-*, with pairs of its own.
Radius
--radius, then the Tailwind radius tokens derived from it, such as --radius-lg: var(--radius).

The contrast is the WCAG 2 ratio of the two colors as the frame paints them, for the mode on screen, so bg=dark shows the ratio of the dark pair. A translucent color counts over what lies under it. The level follows the ratio:

AAA
7:1 and up.
AA
4.5:1 and up, enough for body text.
AA large
3:1 and up, enough for large text only.
fail
Below 3:1.

See the pairs of the shadcn/ui example and its radius.

Material UI

One preset, fed by the theme module that foundations.theme names or, without one, by the --mui-* custom properties that cssVariables: true writes. With both, the theme module wins. The blocks:

Material UI writes most palette colors a second time as …Channel properties, such as --mui-palette-primary-mainChannel: 91 75 219, for colors with alpha. The preset leaves them out, and each block that had some says how many in its note. Material UI 9.5 writes no breakpoints and no transitions as custom properties, so those blocks show only with a theme module.

With a theme module, the reporter also builds Material UI's defaults with the project's own createTheme(), from the same light and dark color schemes and cssVariables as the theme and nothing else. Each token with the same value carries the default badge. A typography variant counts only when every part matches. When only the light or only the dark value matches, the badge shows only while that mode is on screen, as the stage background picks it. A derived value such as contrastText counts when it comes out the same. Only a theme module marks defaults, never the --mui-* custom properties. When @mui/material/styles does not import, every token stays the project's own and the diagnostics get one sentence. The Material UI example runs on CSS variables with its theme module, so its --mui-* give way to the module. See its palette, where only Primary and Secondary are its own, and its typography.

When Foundations opens for a project that uses Material UI without a theme module or --mui-*, it says what to set: “To show the Material UI theme here, name its module in foundations: { theme: 'src/theme.ts' }, which also marks Material UI's defaults, or create the theme with cssVariables: true.” Without any token, the page holds only the heading and that sentence.

Other design systems

Custom properties that no preset takes form blocks by name prefix, within each section. Names that share their first two parts, such as --chakra-colors-gray-50 and --chakra-colors-bg, form a block when there are at least two. Its title and prefix come from the longest prefix they share: Chakra colors, --chakra-colors-*. Names of two parts group by the first. The rest show under Custom properties. Chakra UI, Mantine and Radix Themes show this way.

The tokens of a plain theme module group by their parent path, so colors.ink shows in a block Colors, colors.*, as in the jsdom example.

Type styles

A custom property whose name holds font-family, font-weight, font-size, line-height or letter-spacing shows in Typography with a sample of that part. The part may sit anywhere in the name and be written in camelCase, in the plural or as one word, as in --font-size-lg, --heading-fontSize, --chakra-font-sizes-md or --font-lineheight-1. It wins over the Tailwind prefixes, so --font-size-lg is a size and not a font family.

Custom properties that end in a part and share the name before it form one type style, as Style Dictionary and Tokens Studio write them. --type-title-font-size, --type-title-line-height and --type-title-font-weight show as one token, --type-title-*: a sample line in the whole style, the font size as its value, and its parts under it. A style needs a font size and at least one other part, so --link-font-weight and --link-letter-spacing stay two rows. The sample paints through the custom properties, so the dark variant applies, and the parts show their light values. Styles group by name prefix like any custom property, so --type-title-* and --type-body-* form a block Type, --type-*. Custom properties that a preset takes, such as --mui-*, never form a style.

A plain theme module forms its type styles from objects. An object with a fontSize and at least one more of fontFamily, fontWeight, lineHeight, letterSpacing and textTransform, such as typography.title, is one token with its parts, in the block of its parent path, typography.*. A number is in px for a size and a letter spacing, as React writes it. The object's other keys, such as a variant nested in it, stay tokens of their own. An object whose fontSize is a scale, such as { sm: '14px' }, is no style. A weight or a line height written as a string, such as '600' or '1.5', counts as one when its path names it, as in fontWeights.semibold.

The dark variant #

The stage's background switch sits at the top of the view too, with the same four swatches as the viewport toolbar: auto, light, dark and transparent. It is part of the link as bg. dark applies the dark variant the project declares:

light and auto show the light variant. transparent shows it on the checkerboard. Under dark, when the project has no dark variant and no theme modes, the view shows the hint no dark variant found, except on a page that holds only the Material UI setup hint. The inspector's dark variant row names the one the project declares.

The stage's switch uses the same result. Under dark, a replayed frame, a thumbnail and the test in Live get the class or attribute that the dark variant row names (background).

The viewer theme, the switch in the header, never changes a specimen. It colors only the panel around them.

Compare the dark variant of the shadcn/ui example, a .dark class, in its colors, that of the browser-mode example, prefers-color-scheme, in its colors, and that of the Material UI example, the prefers-color-scheme rule of its CSS variables beside its theme modes, as its inspector row says, in its colors.

Limits #

Foundations reads only the CSS that the tests load. The Tailwind 4 theme comes from an unstable API, the config of Tailwind 3 is not read, and Chakra UI, Mantine and Radix Themes show in generic blocks by name prefix. Limitations lists the workarounds.