Palettes

A palette is a hue/chroma recipe. It generates a continuous range of tones (0–100) in HCT space. Semantic color tokens such as primary and surface then choose a tone from that palette.

Standard palettes

Each built-in variant derives these five palettes from sourceColor:

PaletteRole
primaryMain brand color
secondaryComplementary accent
tertiaryAdditional accent with a variant-specific hue transformation
neutralSurfaces, backgrounds, borders and secondary text
errorError states

The standard variants choose the hue and chroma differently. Leave these palettes untouched when you want the selected variant to retain its intended relationships.

Overriding a standard palette

The palettes key in theme.config.ts can replace a standard palette or add a custom one. A callback receives the current Context and returns a hue and chroma. When it replaces an existing palette, its second argument is the inherited palette recipe for the current context:

ts
// theme.config.ts
import { defineConfig } from '@udixio/tailwind';

export default defineConfig({
  sourceColor: '#6750A4',
  palettes: {
    primary: ({ sourceColor }) => ({
      hue: sourceColor.hue + 30,
      chroma: 60,
    }),
    tertiary: (_context, base) => ({
      ...base!,
      chroma: base!.chroma + 10,
    }),
    neutral: () => ({
      hue: 200,
      chroma: 6,
    }),
  },
});

The callback is evaluated again when a context property it reads changes. A palette has no tone of its own: the tone of a Color returned by a callback is not used for palette generation.

PaletteCallback

ts
type PaletteCallback = (
  context: Context,
  base?: { hue: number; chroma: number },
) => { hue: number; chroma: number };

The Context exposes sourceColor, isDark, contrastLevel and variant. The callbacks used by the built-in variants are ordinary PaletteCallback values and do not receive a base. For a standard palette override, base is recalculated from the active variant whenever the context changes. Return both coordinates when no inherited base exists.

Custom palettes (Udixio variant)

With the Udixio variant, a palette added under a custom key automatically generates semantic tokens for that key:

ts
// theme.config.ts
import { defineConfig } from '@udixio/tailwind';
import { Variants } from '@udixio/theme';

export default defineConfig({
  sourceColor: '#6750A4',
  variant: Variants.Udixio,
  palettes: {
    brand: '#FF5722',
    info: ({ sourceColor }) => ({
      hue: sourceColor.hue + 90,
      chroma: 50,
    }),
  },
});

For brand, the system generates:

  • --color-brand / .bg-brand
  • --color-on-brand / .text-on-brand
  • --color-brand-container / .bg-brand-container
  • --color-on-brand-container / .text-on-brand-container

The fixed roles are generated too. See Color tokens for the available token names.

Simple palette values

A fixed custom palette can be a hex string:

ts
palettes: {
  accent: '#E91E63',
}

At the lower level, Color is also accepted as a palette input. Its tone is ignored because a palette spans every tone:

ts
import { Color } from '@udixio/theme';

palettes: {
  accent: Color.fromHex('#E91E63'),
}

Use a callback when the palette depends on the current context:

ts
palettes: {
  accent: ({ sourceColor }) => ({
    hue: sourceColor.hue + 30,
    chroma: sourceColor.chroma,
  }),
}

These snippets are fragments of the palettes field; place them in theme.config.ts as shown above.

Example: two-color theme

ts
// theme.config.ts
import { defineConfig } from '@udixio/tailwind';
import { Variants } from '@udixio/theme';

export default defineConfig({
  sourceColor: '#1565C0',
  variant: Variants.Udixio,
  palettes: {
    secondary: ({ sourceColor }) => ({
      hue: sourceColor.hue + 180,
      chroma: sourceColor.chroma,
    }),
    accent: '#FF6D00',
  },
});

For direct palette manipulation through api.palettes.get(), api.palettes.sync() or api.palettes.override(), see Palettes API.