Skip to content

Consume design tokens as CSS custom properties - #3261

Merged
enf0rc3 merged 1 commit into
mainfrom
wl/design-system-tokens-css
Jul 28, 2026
Merged

Consume design tokens as CSS custom properties#3261
enf0rc3 merged 1 commit into
mainfrom
wl/design-system-tokens-css

Conversation

@enf0rc3

@enf0rc3 enf0rc3 commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

What

@octopusdeploy/design-system-tokens now ships its tokens as four stylesheets (added in OctopusDeploy/OctopusDeploy#45543). This site is Astro with no React runtime, so it has no Theme component to paint them and the package's TypeScript exports are unusable here.

HtmlHead.astro imports the four files. Vite resolves the ./css/*.css subpath export and bundles them into one hashed stylesheet, so nothing is vendored and nothing can drift from the installed version.

File Contains Selector
globals.css Spacing, radius, font size, other scales :root
textTheme.css Typography shorthands, font families :root
lightTheme.css Light colours and shadows [data-theme="light"]
darkTheme.css Dark colours and shadows [data-theme="dark"]

Why the theme attribute moves from <body> to <html>

lightTheme.css and darkTheme.css select on an unscoped [data-theme="..."], by design, so any element can be a theme root. Our own CSS scopes to html[data-theme='dark'], which made the hardcoded data-theme="dark" on <body> inert — but the token stylesheets do match it, and would force dark tokens on every page regardless of the toggle.

<html> also gains data-theme="light" as a no-JS default. The inline script in HEADER_SCRIPTS normally sets it before paint; without the attribute, neither theme stylesheet matches and no colour token resolves.

Testing

Verified locally that a site variable can point at a token and that both themes follow, by temporarily pointing --color-text at --colorTextPrimary and --octo-blue at --colorTextLinkDefault:

token resolved site var rendered
light #282F38 #282F38 rgb(40, 47, 56)
dark #F4F6F8 #F4F6F8 rgb(244, 246, 248)

The token themes itself, so the matching html[data-theme='dark'] override in vars.css became redundant — two declarations collapse to one. vars.css loads before the token stylesheet and still resolves correctly, because var() resolves at use time rather than declaration time.

Those experiments were reverted. This PR is a visual no-op: 1,184 custom properties are defined and nothing consumes them yet. Production build verified — 2,697 pages, one 48.5KB stylesheet (7KB gzipped) in dist/_astro/, :root plus both [data-theme] blocks present.

Follow-ups

Migrating vars.css onto tokens will come as separate PRs, grouped so each is independently reviewable and revertible: links, then text, then surfaces and borders.

🤖 Generated with Claude Code

@octopusdeploy/design-system-tokens now publishes its tokens as four
stylesheets, so the docs site can consume them directly instead of
generating its own copy from the package's TypeScript exports.

HtmlHead.astro imports them. Vite resolves the ./css/*.css subpath export
and bundles them into one hashed stylesheet, so nothing is vendored and
nothing can drift from the installed package version.

The theme attribute moves from <body> to <html>. lightTheme.css and
darkTheme.css select on an unscoped [data-theme="..."] so that any element
can be a theme root. The site's own CSS scopes to html[data-theme='dark'],
which made the hardcoded data-theme="dark" on <body> inert - but the token
stylesheets do match it, and would force dark tokens on every page
regardless of the toggle. <html> also gains data-theme="light" as a no-JS
default, since the inline script in HEADER_SCRIPTS is what normally sets it.

No visual change: 1,184 custom properties are defined and nothing consumes
them yet.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Comment thread src/layouts/Default.astro
<html dir={textDirection} lang={lang} class="initial">
<html dir={textDirection} lang={lang} class="initial" data-theme="light">
<Head frontmatter={frontmatter} headings={headings} lang={lang} />
<body data-theme="dark">

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This actually caused a "flash-bang" on load for dark-mode, have a side pr to tidy the component up (plus we can also improve it to support browser / system defaults too.

The current js theme selector will set the data-theme="dark" on the element, overwriting this one.

@team-marketing-branch-protections

Copy link
Copy Markdown

Pull request environment is available at https://stoctodocspr3261.z22.web.core.windows.net.

You can view the ephemeral environment status in Octopus Deploy.

This environment will be automatically deprovisioned when the pull request is closed, or after 7 days of inactivity.

@borland borland 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.

I had a look at the staging site and all looks well. Approved

@enf0rc3
enf0rc3 merged commit a977dcc into main Jul 28, 2026
8 of 10 checks passed
@enf0rc3
enf0rc3 deleted the wl/design-system-tokens-css branch July 28, 2026 20:22
enf0rc3 added a commit that referenced this pull request Jul 28, 2026
#3261 added the token CSS, which defines its custom properties only under
[data-theme='light'] and [data-theme='dark'] with nothing at :root, and added a
server-rendered data-theme="light" on <html> so the attribute is present even
without scripting. Both are kept: ThemeScript.astro resolves the real value
before first paint on top of that default.

- Point the HtmlHead token comment at ThemeScript.astro rather than
  HEADER_SCRIPTS, which no longer holds the theme script.
- Spell out in theme.ts why the attribute has to be unconditional.
- Add a javaScriptEnabled: false test so the server-rendered default cannot be
  dropped again without a failure.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
enf0rc3 added a commit that referenced this pull request Jul 28, 2026
#3261 added the token CSS, which defines its custom properties only under
[data-theme='light'] and [data-theme='dark'] with nothing at :root, and added a
server-rendered data-theme="light" on <html> so the attribute is present even
without scripting. Both are kept: ThemeScript.astro resolves the real value
before first paint on top of that default.

- Point the HtmlHead token comment at ThemeScript.astro rather than
  HEADER_SCRIPTS, which no longer holds the theme script.
- Spell out in theme.ts why the attribute has to be unconditional.
- Add a javaScriptEnabled: false test so the server-rendered default cannot be
  dropped again without a failure.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.

3 participants