App-owned tokens and themes

Semantic CSS tokens, data-theme light/dark/system, and cookie-backed preference without a UI runtime

Page actions AI-ready formats and sharing
Open LLM text
Share with AI
Ask Claude Ask ChatGPT Ask Gemini Ask Copilot

Overview

Generated Chirp apps own their visual identity.chirp newcopies ordinary CSS and a small preference helper into the project — not a token registry, CSS-in-Python API, or frontend build. The contract matches RFC 025.

What the scaffold writes

static/css/
  tokens.css       # semantic custom properties
  base.css         # reset + element defaults
  components.css   # reusable component styles
  patterns.css     # product compositions
  pages.css        # route-level layout
static/js/
  theme.js         # progressive enhancement (no Alpine)
  interactions.js  # empty hook for app scripts
theme.py           # cookie preference helpers
pages/_context.py  # exposes theme (+ current_path) to layouts

Filenames are scaffold convention. Rename or merge them freely; Chirp does not error on different CSS paths.

Root theme attributes

Layouts render the preference on<html>:

<html lang="en" data-theme="{{ theme }}">

Allowed data-theme values: light, dark, system(default when unset). Optionaldata-skin and data-densityare extension points — define allowlists intheme.pybefore emitting them.

First paint does not need an inline script. The server setsdata-themefrom the cookie, andtokens.css maps data-theme="system"through prefers-color-scheme. That keeps CSP script-src free of unsafe-inline.

Preference persistence

Posture Authority
Anonymous Same-sitechirp_theme cookie (HttpOnly, SameSite=Lax)
Authenticated (later) Prefer an account setting that still drives the same root attribute

Local storage is only a cross-tab sync hint intheme.js. Navigation output must not depend on a client-only preference.

The no-JavaScript path is a plain form POST to/theme(CSRF-protected) that sets the cookie and redirects. With script allowed,theme.jsupdates data-themeimmediately on radio change, then the same form persists it.

HTMX swaps target page regions, not<html>, so root theme state survives boosted navigation. Full reloads re-read the cookie.

Customize ownership

  1. Edit token values instatic/css/tokens.css.
  2. Style components next totemplates/components/ in components.css.
  3. Keep product vocabulary inpatterns.css / templates/patterns/.
  4. ExtendSKINS / DENSITIES in theme.pyonly with values you validate.

Do not render user-controlled CSS text. Prefer allowlisted attribute values or a generated stylesheet with fixed property names.

Accessibility

Scaffold CSS keeps:focus-visible, forced-colors, and prefers-reduced-motionusable. Theme changes must not rely on color alone — the control exposes text labels (Light / Dark / System).