Colors
@vyui/kit ships six configurable semantic colors (primary, secondary, success, info, warning, error) plus neutral, which is always present but kept out of the configurable list (mirrors nuxt/ui, which excludes neutral from theme.colors too). Source of truth: packages/kit/src/theme/color-constants.js.
Default semantic → Tailwind-palette mapping:
| Semantic | Palette |
|---|---|
primary | green |
secondary | blue |
success | emerald |
info | sky |
warning | amber |
error | red |
neutral | slate |
Not the obvious 1:1 (success isn't stock green, info isn't stock blue): Tailwind's base yellow / blue / green read too washed out at shade-500 for contrast on white, so amber / sky / emerald stand in.
Three CSS-variable tiers
packages/kit/src/style.css defines every color as three tiers of custom property. This is the mental model to keep in your head when overriding or reading theme files:
- Palette covers
--ui-color-{semantic}-{50..950}, the full Tailwind shade scale per semantic color (e.g.--ui-color-primary-500: theme('colors.green.500')). Powers ramp utilities:bg-primary-500,border-error-200. - Mode covers
--ui-{semantic}(e.g.--ui-primary), a single active shade per color mode (-500in light,-400in dark). Powers shorthand utilities:bg-primary,text-error. - Semantic / surface holds role-based tokens about UI role, not a specific color, that flip entirely between light and dark:
text-dimmed/muted/toned/default/highlighted/inverted,bg-default/muted/elevated/accented/inverted,border-default/muted/accented/inverted. Component themes use these for text, surfaces, and borders instead of rawneutral-*classes, so components adapt to dark mode automatically with zerodark:variants.
One nuance that trips people up: the palette tier's neutral ramp does not invert. bg-neutral-100 is the literal same slate shade in light or dark mode, because picking a raw ramp class is a "you picked a literal shade" contract. Only the semantic/surface tier flips. Reach for bg-muted, not bg-neutral-100, for anything that should adapt to dark mode.
Configuring colors
Two ways to customize, depending on how far you need to go.
Rebrand via CSS only by overriding the --ui-color-{semantic}-{shade} variables in your own stylesheet, after importing @vyui/kit/style.css. No build step, no config file:
@import '@vyui/kit/style.css';
:root {
--ui-color-primary-500: #6366f1;
--ui-color-primary-600: #4f46e5;
}
This only rebrands a color already in the configurable set; it doesn't add a new slot.
Add a new color slot such as tertiary by noting that the Tailwind preset has to generate the classes while the runtime has to select the same set. Author the color list once and feed it to both planes:
import type { VyUIPluginOptions } from '@vyui/kit'
import { COLORS } from '@vyui/kit/tailwind'
export default {
ui: { colors: [...COLORS, 'tertiary'] },
} satisfies VyUIPluginOptions
import vyuiConfig from './vyui.config'
import { createVyuiPreset } from '@vyui/kit/tailwind'
export default {
presets: [lynxPreset, createVyuiPreset(vyuiConfig)],
}
import vyuiConfig from './vyui.config'
import { provideVyUI } from '@vyui/kit' // or: app.use(VyUI, vyuiConfig) on web
provideVyUI(app, vyuiConfig)
createVyuiPreset dev-warns if a listed color has no backing --ui-color-* var, so a "class resolves to nothing" mistake surfaces at build time instead of on device. To also type-check tertiary on every component's color prop:
declare module '@vyui/kit' {
interface VyuiColorRegistry { tertiary: true }
}
Then add the --ui-color-tertiary-{50..950} CSS-var block, generating the .d.ts and the CSS together with:
node node_modules/@vyui/kit/scripts/gen-colors.mjs --colors tertiary=indigo
See the @vyui/kit README for the full flow, or Installation for how the config object fits alongside the rest of the plugin setup.