Theming Reference
The host (wippy/facade) provides the theme. Both micro frontend apps and web components consume it. The variable catalog below is the shared vocabulary — delivery specifics are in Theming: Micro Frontend Apps and Theming: Web Components.
YAML always wins. CSS variables set by the facade/host cascade to child iframes and (for custom properties only) into shadow DOM. Stylesheets do not cross shadow DOM boundaries.
Reference — CSS variables
All variables are defined in theme-config.css and set on :root. At runtime, the host injects the real theme — these serve as the dev-time fallback and contract.
Primary palette (11 vars)
Base: --p-primary (default: rgb(0, 95, 178))
| Variable | Value |
|---|---|
--p-primary-50 |
color-mix(in srgb, var(--p-primary) 5%, white) |
--p-primary-100 |
color-mix(in srgb, var(--p-primary) 10%, white) |
--p-primary-200 |
color-mix(in srgb, var(--p-primary) 20%, white) |
--p-primary-300 |
color-mix(in srgb, var(--p-primary) 30%, white) |
--p-primary-400 |
color-mix(in srgb, var(--p-primary) 40%, white) |
--p-primary-500 |
var(--p-primary) (base) |
--p-primary-600 |
color-mix(in srgb, var(--p-primary) 80%, black) |
--p-primary-700 |
color-mix(in srgb, var(--p-primary) 70%, black) |
--p-primary-800 |
color-mix(in srgb, var(--p-primary) 60%, black) |
--p-primary-900 |
color-mix(in srgb, var(--p-primary) 50%, black) |
--p-primary-950 |
color-mix(in srgb, var(--p-primary) 40%, black) |
Secondary palette (11 vars)
Base: --p-secondary (default: #6f7385)
Same 50–950 structure as primary, derived via color-mix on --p-secondary, but with its own percentage ladder — steps 300/400/700/800/950 use different mix percentages than primary, so do not assume primary's exact step values when overriding the secondary base.
Surface palette (13 vars)
Fixed light-to-dark scale — 0 is always lightest, 950 always darkest. The scale does NOT flip with dark mode. The light scale is the neutral Tailwind gray (no warm cast); the dark scale is a separate warm-toned ramp, so most levels differ between modes — only 0 and 50 are shared. Dark levels 600–950 carry the warmest undertones.
| Variable | Light value | Dark value |
|---|---|---|
--p-surface-0 |
#ffffff |
#fff |
--p-surface-50 |
#fafafa |
#fafafa |
--p-surface-100 |
#f5f5f5 |
#f4f4f5 |
--p-surface-200 |
#e5e5e5 |
#e4e4e7 |
--p-surface-300 |
#d4d4d4 |
#d4d4d8 |
--p-surface-400 |
#a3a3a3 |
#a1a1aa |
--p-surface-500 |
#737373 |
#71717a |
--p-surface-600 |
#525252 |
#545250 (warm) |
--p-surface-700 |
#404040 |
#403e3c (warm) |
--p-surface-800 |
#262626 |
#2b2927 (warm) |
--p-surface-850 |
color-mix(in srgb, var(--p-surface-800) 50%, var(--p-surface-900)) |
color-mix(in srgb, var(--p-surface-800) 50%, var(--p-surface-900)) |
--p-surface-900 |
#171717 |
#1c1a19 (warm) |
--p-surface-950 |
#0a0a0a |
#0f0e0d (warm) |
Danger / Warn / Success / Info / Help / Accent palettes
Each has a base var and an 11-step scale (50–950) derived via color-mix, same pattern as primary.
| Family | Base variable | Default color | Purpose |
|---|---|---|---|
danger |
--p-danger |
rgb(239, 68, 68) (red-500) |
Errors, destructive actions |
success |
--p-success |
rgb(34, 197, 94) (green-500) |
Success states, confirmations |
warn |
--p-warn |
rgb(249, 115, 22) (orange-500) |
Warnings, caution |
info |
--p-info |
rgb(14, 165, 233) (sky-500) |
Informational messages |
help |
--p-help |
rgb(168, 85, 247) (purple-500) |
Help, hints |
accent |
--p-accent |
rgb(20, 184, 166) (teal-500) |
Highlights, special callouts |
Override the base var to retheme the full scale — the 50–950 range auto-derives via color-mix. No dark-mode override block is needed.
Semantic variables (mode-aware)
These flip with dark mode — use these for theme-dependent styling. Do not use numbered surface vars (--p-surface-N) for semantic colors.
| Variable | Light | Dark |
|---|---|---|
--p-primary-color |
primary-500 |
primary-400 |
--p-primary-contrast-color |
surface-0 |
surface-900 |
--p-primary-hover-color |
primary-600 |
primary-300 |
--p-primary-active-color |
primary-700 |
primary-200 |
--p-text-color |
surface-700 |
surface-0 |
--p-text-hover-color |
surface-800 |
surface-0 |
--p-text-muted-color |
surface-500 |
surface-400 |
--p-text-hover-muted-color |
surface-600 |
surface-300 |
--p-content-background |
surface-0 |
surface-900 |
--p-content-border-color |
surface-200 |
surface-700 |
--p-content-hover-background |
surface-100 |
surface-800 |
--p-content-hover-color |
surface-800 |
surface-0 |
--p-highlight-background |
primary-50 |
primary-400 @ 16% |
--p-highlight-color |
primary-700 |
white @ 87% |
--p-highlight-focus-background |
primary-100 |
primary-400 @ 24% |
--p-highlight-focus-color |
primary-800 |
white @ 87% |
--p-content-border-radius |
6px |
6px |
Reference — Dark mode
Variables switch at @media (prefers-color-scheme: dark). Key changes:
--p-primarybase shifts fromrgb(0, 95, 178)torgb(0, 125, 178)(brighter)--p-primary-colorshifts fromprimary-500toprimary-400--p-content-backgroundshifts fromsurface-0tosurface-900--p-text-colorshifts fromsurface-700tosurface-0- Surface levels diverge between modes — light uses neutral gray, dark uses a separate warm ramp (only
0and50are shared); levels 600–950 carry the warmest undertones
Universal rule: every level of custom CSS must produce a sensible result in both light and dark modes.
.my-thing {
background: var(--p-content-background);
color: var(--p-text-color);
}
/* Only needed when you genuinely require mode-specific raw values: */
.my-thing { background: #ffffff; color: #111111; }
@media (prefers-color-scheme: dark) {
.my-thing { background: #18181b; color: #e5e5e5; }
}
In cssVariables YAML, use @light / @dark keys:
cssVariables:
"--p-primary": "#005fb2"
"@light":
"--p-content-background": "#fafafa"
"@dark":
"--p-content-background": "#1c1a19"
Reference — Tailwind severity utility classes
Provided by tailwindcss-primeui plugin (included in the shared Tailwind preset). Work with bg-, text-, border-, outline-, ring- prefixes.
Rule: always use semantic severity classes over raw Tailwind color names when the color conveys meaning. Never text-red-500 for danger, bg-green-100 for success, etc.
| Class suffix | Maps to |
|---|---|
primary |
--p-primary-color |
primary-{0,50,100,...,950} |
Full primary shade range |
surface-{0,50,100,...,950} |
Full surface shade range |
danger-{50..950} |
--p-danger scale |
success-{50..950} |
--p-success scale |
warn-{50..950} |
--p-warn scale |
info-{50..950} |
--p-info scale |
help-{50..950} |
--p-help scale |
accent-{50..950} |
--p-accent scale |
secondary-{50..950} |
--p-secondary scale |
Semantic color utilities:
| Class | Maps to |
|---|---|
.text-color |
--p-text-color |
.text-muted-color |
--p-text-muted-color |
.bg-highlight |
Highlighted state (selected items, active rows) |
.border-surface |
--p-content-border-color |
.rounded-border |
--p-content-border-radius |
Animation utilities: .animate-fadein, .animate-fadeout, .animate-slidedown, .animate-slideup, .animate-scalein, .animate-fadeinleft, .animate-fadeinright, .animate-fadeinup, .animate-fadeindown, .animate-duration-{ms}, .animate-delay-{ms}, .animate-ease-*.
Reference — Host UI customization (--wippy-host-* + BEM classes)
Override host chrome through AppConfig.theming.host.cssVariables / customCSS. Shared brand theme belongs in AppConfig.theming.global; child-only overrides belong in AppConfig.theming.children and are projected into each child iframe as config.theming.global.
Always scope class-based overrides to .wippy-host-app to prevent leaking into child iframes.
Layout & sidebar
| Variable | Default | Description |
|---|---|---|
--wippy-host-sidebar-width-open |
16rem |
Sidebar width when expanded |
--wippy-host-sidebar-width-closed |
3.5rem |
Sidebar width when collapsed |
BEM classes (scope with .wippy-host-app):
| Class | Element |
|---|---|
.layout |
Root layout wrapper |
.layout__sidebar |
Sidebar container |
.layout__sidebar-header |
Sidebar header (logo + toggle) |
.layout__sidebar-nav |
Navigation list area |
.layout__main |
Main content area (right of sidebar) |
Splitter gutter
| Variable | Default | Description |
|---|---|---|
--wippy-host-splitter-width |
1px |
Visible line width |
--wippy-host-splitter-hit-area |
10px |
Draggable hit area width (transparent) |
--wippy-host-splitter-color |
var(--p-surface-200) (light) / var(--p-surface-600) (dark) |
Line color |
Chat messages
| Variable | Default | Description |
|---|---|---|
--wippy-host-message-radius |
1rem |
Message bubble border radius |
--wippy-host-message-padding-x |
1rem |
Message horizontal padding |
--wippy-host-message-padding-y |
0.5rem |
Message vertical padding |
--wippy-host-message-user-bg |
var(--p-primary-50) |
User message background |
--wippy-host-message-agent-bg |
var(--p-yellow-50) (light) / var(--p-surface-800) (dark) |
Agent message background — note --p-yellow-50 is undefined in theme-config.css, so set this var (e.g. to var(--p-warn-50)) for a valid light background |
--wippy-host-tool-bg |
var(--p-help-50) |
Tool call background |
--wippy-host-tool-border |
var(--p-help-300) |
Tool call left border |
--wippy-host-avatar-size |
2rem |
Message avatar diameter |
BEM classes (scope with .wippy-host-app):
| Class | Element |
|---|---|
.chat-message |
Message row container |
.chat-message--user |
User message modifier |
.chat-message--agent-message |
Agent message modifier |
.chat-message--tool |
Tool call message modifier |
.chat-message--error |
Error message modifier |
.chat-message__avatar |
Avatar wrapper |
.chat-message__avatar-icon |
Avatar icon circle |
.chat-message__content |
Message bubble |
.chat-message__body |
Message text content |
.chat-message__footer |
Timestamp row |
.chat-message__tool-name |
Tool name label |
.chat-message__tool-icon |
Tool icon |
.chat-message__agent-content |
Agent name system line |
.chat-message__model-content |
Model name system line |
.chat-message__files |
Attached files row |
.chat-tool-group |
Inline tool call badge group |
.chat-tool-group__badge |
Individual tool badge |
.chat-tool-group__badge--success |
Completed tool badge |
.chat-tool-group__badge--error |
Failed tool badge |
.chat-tool-group__badge--processing |
In-progress tool badge |
.chat-tool-group__icon |
Badge icon |
Chat input
BEM classes (scope with .wippy-host-app):
| Class | Element |
|---|---|
.chat-input |
Input bar container |
.chat-input__group |
Input field + buttons wrapper |
.chat-input__textarea |
Message textarea |
.chat-input__attach-button |
Attachment button |
.chat-input__send-button |
Send button |
.chat-input__stop-button |
Stop generation button |
.chat-input__upload-list |
Upload queue list |
.chat-input__prompts |
Suggested prompts area |
Chat container
BEM classes (scope with .wippy-host-app):
| Class | Element |
|---|---|
.chat-container |
Outer chat wrapper |
.chat-container--selected |
Has active session |
.chat-container--non-selected |
No session selected |
.chat-container__empty-state |
Empty state wrapper |
.chat-container__empty-state-icon |
Empty state icon |
.chat-container__empty-state-title |
Empty state heading |
.chat-container__empty-state-description |
Empty state text |
.chat-container__drop-zone |
File drag-and-drop overlay |
.chat-container__drop-zone-icon |
Drop zone icon |
Session selector
BEM classes (scope with .wippy-host-app):
| Class | Element |
|---|---|
.session-selector |
Selector wrapper |
.session-selector__dropdown |
Dropdown component |
.session-selector__option |
Session option row |
.session-selector__active-dot |
Active session indicator |
Root
| Class | Element |
|---|---|
.wippy-host-app |
Application root element — scope all host-only CSS overrides to this |
Anti-patterns (REJECT list)
These apply to both micro frontend apps and web components.
Color / semantic vars
- Hardcoded hex/rgb for semantic colors:
color: #ef4444,background: rgb(34, 197, 94). Always usevar(--p-danger-*)/var(--p-success-*)/var(--p-warn-*)/ etc. - Raw Tailwind color classes for semantic meaning:
text-red-500,bg-green-100,border-yellow-300. Use severity classes:text-danger-500,bg-success-100,border-warn-300. - Numbered
--p-surface-Nfor theme-dependent semantic colors (e.g.color: var(--p-surface-700)for "muted text"). Use semantic aliases:var(--p-text-color),var(--p-text-muted-color),var(--p-content-background),var(--p-content-border-color). - Component-level custom color palettes (
--my-app-red,--feature-blue) declared without a documented design reason. - Using severity tokens in decorative contexts (
--p-danger-500for "red chart category") — that implies meaning the element doesn't have.
Placement / scope
:root { --p-* }overrides inside a child app'ssrc/styles.css. Put--p-*overrides in facade theming (theming.global/theming.children) or per-pageconfigOverrides.customization.cssVariables.- Raw
.p-button { … }/.p-dialog { … }selectors inside a child app'ssrc/styles.css. Put PrimeVue selector overrides in facade theming or per-pageconfigOverrides.customization.customCSS. - App-side
<style>blocks defining@media (prefers-color-scheme: dark)rules that retune host vars. - Theme-related CSS in
src/styles.css— if it's a host-styled component, it belongs in the facade.
Components / API
- Reimplementing a PrimeVue component from scratch (custom Toast, Dialog, Accordion, Select). Use the PrimeVue component +
customCSSoverrides. useToast()/useConfirm()from PrimeVue in micro frontend app code. Usehost.toast(...)/host.confirm(...).- Components that redeclare
--p-*vars they should inherit (:host { --p-primary-500: #abc }). <Button icon="pi pi-plus">— use<Icon>from@iconify/vueinstead of thepi-*icon font.
Build / config
- Importing
primevue/configdirectly to install the PrimeVue plugin. Use@wippy-fe/theme/primevue-plugin. - Adding
primeVueCssUrlto a WC'shostCssKeyswhen the WC doesn't render PrimeVue components. - Setting
proxy.injections.tailwindConfig: truein a Vite-built app (legacy runtime-Tailwind path). - Externalizing
@wippy-fe/themein a WC's Vite config — theme assets must be bundled into the WC.
Related docs
- micro-frontend-app-theming.md — how micro frontend apps receive and configure theme injection
- web-component-theming.md — how web components receive the theme through shadow DOM
- micro-frontend-app.md — building Wippy micro frontend apps
- web-component.md — building Wippy web components
- host-less-mode.md — dev overlay and CSS injection in host-less mode
- compliance-checklist.md — full REJECT/WARN rules for theming