Skip to content

Extend the theme contract with kit tokens and add sample UI to the theme dashboards - #5989

Merged
burieberry merged 13 commits into
mainfrom
cs-12723-upstream-kit-tokens
Sep 5, 2026
Merged

Extend the theme contract with kit tokens and add sample UI to the theme dashboards#5989
burieberry merged 13 commits into
mainfrom
cs-12723-upstream-kit-tokens

Conversation

@burieberry

@burieberry burieberry commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Extends the theme contract with the generic tokens a component kit needs beyond shadcn's set, so a kit's cards and the boxel-ui components nested in them read from one contract, and gives the theme dashboards realistic specimens to judge a theme on. Builds on #5982 (merged).

Linear: CS-12723 (parent CS-12711).

Naming decisions to review

Names are Boxel's, not copied from the kit. The rules applied:

  • Bare names, following the --success/--warning precedent for anything theme.css declares.
  • Map before adding. A kit token that is the same knob as an existing token, or a step on a scale already derived from a contract knob (--boxel-sp-*, --boxel-border-radius-*, --boxel-font-size-*), gets no new field.
  • Hue as ink. --x/--x-foreground cover ink on a hue's fill; nothing named the hue used as ink on a neutral surface. Added --x-ink for all eight hues (primary, secondary, accent, destructive, success, warning, info, attention). The default is color-mix(in oklch, var(--x) 60%, var(--foreground)), so a theme that only sets the hue still gets an ink that darkens on light and lightens on dark. The formula is re-declared in .dark because a var() inside a custom property resolves where it is declared, so a dark subtree would otherwise inherit the light-resolved color.

New tokens (30 ThemeVarField fields)

Family Tokens
Surfaces --canvas, --inset, --field (input background; --input is the border), --hover (translucent), --stripe, --selected, --tooltip + --tooltip-foreground
Inks & lines --subtle-foreground (third ink step), --border-strong
Status --info + -foreground, --attention + -foreground, --success-foreground, --warning-foreground, --overlay
Hue as ink --primary-ink, --secondary-ink, --accent-ink, --destructive-ink, --success-ink, --warning-ink, --info-ink, --attention-ink
Charts --chart-6, --chart-7
Size / shadow --control-height (wired into --boxel-form-control-height by CardContainer), --shadow-inset

theme.css declares light and dark defaults for every one, in the same block as the existing contract, so they reset at every themed-card boundary too.

Typography maps onto roles, not new tokens

The kit's flat type ladder maps onto the existing ThemeTypographyField slots. The residue became:

  • two new slots, label (UI/control text) and eyebrow (the tracked-out kicker above a title), emitted as --theme-label-* / --theme-eyebrow-* and derived by CardContainer as --boxel-ui-label-* / --boxel-eyebrow-* with the same fallback shape as the existing slots. The --boxel-label-* family is left alone: it is the Label component's own contract and keeps falling back to the body slot;
  • letterSpacing on TypographyField, so every slot emits --theme-<slot>-letter-spacing and CardContainer derives --boxel-<slot>-letter-spacing. Body, caption, and label follow the theme's base tracking. Nothing applies these yet; that is the components' call.

Space, radius, shadow composites, and control chrome all map onto tokens the contract already has, so no fields were added for them.

Dark defaults at themed-card boundaries

theme.css re-declares the whole light contract on every [data-boxel-theme-scope] so token values can't leak into a themed card. That reset also applied inside dark subtrees, so a themed card in dark chrome rendered every token its theme omitted with the light default. A new @container style(--boxel-color-scheme: dark) block applies the dark contract at those boundaries, keyed off the inherited scheme signal, the same mechanism a card's own .dark variables use. The --boxel-switch/button chrome knobs are deliberately left out of that block so themed cards keep deriving them from their own tokens in both schemes.

Theme dashboards

  • Inherited defaults in the preview. Unset variables in the isolated preview show the value they inherit from the Boxel defaults instead of /* not set */: a swatch painted with the resolved default, the value text, and an "inherited" tag whose tooltip shows the declared expression. The value is read at the swatch's position inside the theme scope, so it follows the light/dark toggle.
  • Wide format. Theme cards open in the wide stack format. The dashboard content, header, and nav share one measure (--dsr-content-max-width, 72rem). Style Reference dropped its whole-card 50rem cap to match.
  • Specimens replace the Components block. Four tabbed scenes built from boxel-ui: Surfaces & Ink (canvas, card, inset well with an input, zebra table with hover and selected rows, tooltip, all eight inks, status chips), Controls (buttons, input, select, switch, progress), Dashboard (stat tiles, chart bars, warning banner), Reading (eyebrow through caption). Every surface carries a pill naming its token. The Brand Guide's UI Components section renders the same specimens.
  • Measured type ladder. Each typography role shows its resolved size, line-height ratio, and weight beside the specimen, re-measured when the theme stylesheet or the light/dark toggle changes.
  • Key tokens recipe. Computed Styles opens with a curated :root excerpt of the tokens that define the look, following the previewed scheme, with a copy button.
  • Fonts section. The visualizer's font previews and CSS Imports list sit side by side when they fit. The Brand Guide gains the same section.
  • Generated CSS blocks scroll. CSSField accepts --css-field-max-height; the dashboards cap it at 40vh with an edge fade driven by a scroll timeline, shown only at an edge with more content beyond it.

Select

BoxelSelect derives its dropdown colors from contract tokens instead of the fixed palette: selected text from --primary-foreground, hover from --muted, highlight-hover mixed from the highlight color. A --boxel-dropdown-hover-text-color override is added and synced into the portaled dropdown.

Tests

  • structured-theme-test: the extended tokens round-trip through setCss and cssVariables; label/eyebrow slots emit theme variables including letter-spacing; unset variables render as inherited with a resolved literal color and follow the dark toggle.
  • theme-card-test: an omitted token resolves to the dark default in the dark preview.
  • theme-dark-boundary-test (boxel-ui): the two dark blocks declare the same tokens with the same values; dark defaults hold inside a dark subtree; a light-forced subtree stays light.

Follow-ups

  • CS-12807: BoxelInput should read --field and --subtle-foreground. The Surfaces specimen remaps those onto the input's wrapper until then.
  • Percy snapshots for the theme cards and Brand Guide change with the new sections.

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Preview deployments

Host Test Results

    1 files  ±0      1 suites  ±0   2h 22m 7s ⏱️ - 8m 17s
4 626 tests +3  4 612 ✅ +3  14 💤 ±0  0 ❌ ±0 
4 641 runs  +3  4 627 ✅ +3  14 💤 ±0  0 ❌ ±0 

Results for commit 17a5649. ± Comparison against earlier commit 09d80f0.

Realm Server Test Results

    1 files  ± 0    200 suites  +1   1h 8m 6s ⏱️ - 4m 56s
2 605 tests +31  2 605 ✅ +31  0 💤 ±0  0 ❌ ±0 
2 644 runs  +31  2 644 ✅ +31  0 💤 ±0  0 ❌ ±0 

Results for commit 17a5649. ± Comparison against earlier commit 09d80f0.

@burieberry
burieberry force-pushed the cs-12723-upstream-kit-tokens branch from a4b7c67 to d99de33 Compare September 3, 2026 17:46
@burieberry
burieberry force-pushed the cs-12723-upstream-kit-tokens branch from d99de33 to c63db45 Compare September 3, 2026 17:50
@burieberry
burieberry marked this pull request as ready for review September 3, 2026 18:57
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 3, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-03T19:00:09.744963Z e720a3e Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e720a3e92b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/boxel-ui/src/styles/theme.css
@burieberry
burieberry requested a review from a team September 3, 2026 19:23

@habdelra habdelra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Claude Code 🤖] This review went after how the new tokens land on code that already exists: name collisions with --boxel-* variables boxel-ui components already read, whether the theme.css defaults hold under the light/dark and themed-card-scope rules, and whether the inherited-swatch resolution does what it is described as doing. It does not judge the naming or visual design of the token set itself, and the acceptance module was not run locally.

The token set and its theme.css defaults hold up; two things block. The new --boxel-label-* slot takes over a variable family Label and FieldContainer already read, silently resizing every card's field labels, and the inherited-swatch resolution does not follow the dark toggle in Style Reference.

On the open thread about dark defaults at themed-card boundaries: the reply there is correct and I verified the mechanism independently. .dark, [data-theme='dark'] matches only an element that itself carries the class or attribute, while :where([data-boxel-theme-scope]) matches the card scope element, so the child declaration wins for every contract token — --background, --card, --border included — not only the ones added here. These tokens follow the existing rule rather than introducing the behavior.

Recommendations, in order:

  1. Rename the new UI-label typography slot, or accept the label resize deliberately and review the Percy diffs for it — see the comment on the ui label block in card-container/index.gts.
  2. Make the inherited-swatch resolution re-run on a color-mode flip, and cover it with a test — see the comment on the resolve modifier in structured-theme-variables.gts. The description's light/dark claim only holds for the theme card today.
  3. Decide whether Switch moves off --input, or soften the --input description — comment on that field.
  4. Fix the Style Reference header measure subtraction, or reword the comment above it.
  5. Drop the unrelated package.json reorder.

Adjacent, out of scope: InheritedSwatch appends a probe span, reads getComputedStyle, and removes it once per unset token, so a blank theme's grid pays a style recalc per swatch on every render and every mode flip. Only worth hoisting to one shared probe in FieldGrid if the dashboard starts feeling slow — not asked of this PR.


Generated by Claude Code

Comment thread packages/boxel-ui/src/components/card-container/index.gts Outdated
Comment thread packages/base/structured-theme-variables.gts Outdated
Comment thread packages/base/structured-theme-variables.gts
Comment thread packages/base/style-reference.gts Outdated
Comment thread packages/base/package.json
Base automatically changed from cs-12721-add-theme-var-fields to main September 4, 2026 17:43
@burieberry
burieberry force-pushed the cs-12723-upstream-kit-tokens branch from b559415 to 47af0bd Compare September 4, 2026 18:32
@burieberry burieberry changed the title Upstream kit surface, status, ink, and typography tokens to the theme contract Extend the theme contract with kit tokens and add specimens to the theme dashboards Sep 4, 2026
@burieberry burieberry changed the title Extend the theme contract with kit tokens and add specimens to the theme dashboards Extend the theme contract with kit tokens and add sample UI to the theme dashboards Sep 4, 2026
@burieberry
burieberry force-pushed the cs-12723-upstream-kit-tokens branch from 47af0bd to 09d80f0 Compare September 4, 2026 21:39
@burieberry
burieberry force-pushed the cs-12723-upstream-kit-tokens branch from 09d80f0 to 17a5649 Compare September 5, 2026 00:17
@burieberry
burieberry merged commit 3a7e0a1 into main Sep 5, 2026
77 checks passed
@burieberry
burieberry deleted the cs-12723-upstream-kit-tokens branch September 5, 2026 00:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants