# A2UI Theming Findings Captured 2026-04-28 while researching how to beautify the table the agent renders via `render_a2ui` without overriding component internals. ## TL;DR - A2UI v0.9 docs prescribe theming through a small set of **documented top-level CSS variables** declared on `:where(:root)` (zero specificity, so host CSS wins without `!important`). - Default theme uses `light-dark()` so tokens self-toggle. Recommended dark-mode coupling: add the documented `a2ui-dark` class on `` whenever Tailwind's `.dark` is on; that flips `color-scheme: dark` and resolves every `light-dark()` to its dark branch. - **In our app, this approach has near-zero visible effect.** We render through `@copilotkit/a2ui-renderer` (React variant), not `@a2ui/lit`. Inspecting the compiled React renderer (`node_modules/.pnpm/@copilotkit+a2ui-renderer@1.56.4/.../catalog/basic/components/*.mjs`), every component uses **hardcoded inline styles**; the only CSS variable consumed across the whole basic catalog is `--a2ui-primary-color`. - This matches open issues `google/A2UI#977` and `#1285` ("React renderer parity is incomplete"). ## Documented token surface (Lit / Angular) From `tech_docs/A2UI/renderers/web_core/src/v0_9/basic_catalog/styles/default.ts`: - Color palette: `--a2ui-color-background`, `--a2ui-color-on-background`, `--a2ui-color-surface`, `--a2ui-color-on-surface`, `--a2ui-color-primary`, `--a2ui-color-primary-light/-dark/-hover`, `--a2ui-color-on-primary`, `--a2ui-color-secondary`, `--a2ui-color-secondary-light/-dark/-hover`, `--a2ui-color-on-secondary`, `--a2ui-color-input`, `--a2ui-color-on-input`, `--a2ui-color-border`. - Borders: `--a2ui-border`, `--a2ui-border-width`, `--a2ui-border-radius`. - Typography: `--a2ui-font-family-title`, `--a2ui-font-family-monospace`, `--a2ui-font-size`, `--a2ui-font-scale`, `--a2ui-font-size-xs..2xl`, `--a2ui-line-height-headings`, `--a2ui-line-height-body`. - Spacing: `--a2ui-grid-base`, `--a2ui-spacing-xs..xl`. Per-component tokens like `--a2ui-card-background` exist but the renderer README and the official theming guide explicitly frame them as catalog-internal, not stable spec. Avoid relying on them. ## Dark-mode coupling A2UI default uses `light-dark(...)` and supports forced modes via `a2ui-light` / `a2ui-dark` classes (see the `:where(.a2ui-dark)` block in `default.ts`). Best practice for a host that uses Tailwind `.dark` on ``: toggle the matching `a2ui-dark` class in lockstep — one effect-driven `useEffect`, or add it directly to the root if the app is dark-only. No need to redeclare every token under `.dark`; the default rules already pick up the right branch through `light-dark()`. ## Footguns in v0.9 - The agent-supplied `theme` payload (e.g. `createSurface.theme.primaryColor`) is **not yet wired** in the basic catalog. Tracked in `google/A2UI#979` (Lit) and `#977` (React). Don't expect agent-side theming to recolor anything in v0.9; only the host CSS does. - `hintedStyles` (h1–h6 mappings) require all keys when overridden — see `google/A2UI#602`. - Tracking issues for the broader theming surface: `google/A2UI#1083`, `#1118`. ## Why this won't move the table in our app `@copilotkit/a2ui-renderer@1.56.4` (React) is what `` plugs in. Its components apply colors and borders as inline `style` props (`backgroundColor: "#fff"`, `border: "1px solid #ccc"`, etc.). Inline styles can only be overridden with `!important` in author CSS, which contradicts the "don't take its freedom" goal. So the documented `--a2ui-*` token contract is currently a **Lit-only surface** for this catalog. ## Practical options for this codebase 1. **Quick win**: set `--a2ui-primary-color: var(--primary)` on `:root`. Real but small effect (primary buttons, links). 2. **Prompt-side polish**: instruct the agent to compose richer A2UI structures — wrap the table in a `Card`, use `usageHint: "h3"` for the section title, insert a `Divider`, group columns with `Row` + `Column` weights — so the renderer's existing inline styles produce a cleaner result. No code change. 3. **Switch renderer**: replace `@copilotkit/a2ui-renderer` with `@a2ui/lit` (or wait for `@a2ui/react` parity). Then every documented `--a2ui-*` token actually applies. Non-trivial migration. 4. **Custom catalog overrides**: register replacement React components for `Row`/`List`/`Card` via `createA2UICatalog`; full control, most invasive, accepts ownership of those components forever. ## Source links - `tech_docs/A2UI/docs/guides/theming.md` - `tech_docs/A2UI/renderers/web_core/src/v0_9/basic_catalog/styles/default.ts` - `tech_docs/A2UI/renderers/lit/README.md` §"CSS-based Basic Catalog Theming" - `https://github.com/google/A2UI/issues/977` (React renderer theming gap) - `https://github.com/google/A2UI/issues/1285` (React renderer parity) - `https://github.com/google/A2UI/issues/1118` (theming surface roadmap) - `https://github.com/google/A2UI/issues/979` (Lit `theme` payload not wired) - `https://github.com/google/A2UI/pull/1079` (v0.9 CSS-variable rollout)