Override tokens for the whole app, one section, or one element.
Every colour, and the corner radius, is a CSS custom property. Components read those properties and nothing else. So customising XiodUI means redefining the properties you care about in your own stylesheet — no config file, no plugin, no wrapper components, and nothing to eject from.
1@import "tailwindcss";2@import "xiod-ui/styles";34/* Your overrides go below the import. That is the entire mechanism. */5:root {6 --primary: #4f46e5;7}That is a complete, working customisation. Every button, link, and focus ring in the app is now indigo. If you only read one section of this page, this was it.
Overrides go after the import
CSS gives the last matching rule the win. Put your :root block above @import "xiod-ui/styles" and the library defaults simply overwrite it. Imports also have to sit at the top of the file, so in practice: imports first, your rules after.
Use :root, not @theme
@theme is where Tailwind defines its own scales. XiodUI's tokens are already wired into Tailwind for you, so they are set on :root like ordinary CSS. Putting them in @theme quietly does nothing.
A colour is rarely alone. --primary is the fill; --primary-foreground is the label printed on that fill, and --ring is the focus outline that should match. Set all three, in both colour schemes.
1@import "tailwindcss";2@import "xiod-ui/styles";34:root {5 --primary: #4f46e5; /* the button fill */6 --primary-foreground: #ffffff; /* the label on that fill */7 --ring: #4f46e5; /* the focus ring, so it matches */89 @variant dark {10 --primary: #a5b4fc; /* lighter, so it reads on a dark page */11 --primary-foreground: #1e1b4b; /* dark text, because the fill is now light */12 --ring: #a5b4fc;13 }14}Do not skip the dark values
Tokens you set only in :root apply in dark mode too, because nothing overrides them back. A brand colour picked to sit on white usually goes muddy on a dark page — most palettes use a lighter, less saturated version at night, and flip the foreground from white to dark to match.
Writing all thirty-odd tokens by hand is real work, and most of it is deciding on greys. It is usually faster to import one of the shipped palettes and change the few tokens you disagree with — the import is just a stylesheet, so your rules below it still win.
1@import "tailwindcss";2@import "xiod-ui/styles";34/* Start from a palette that is already close... */5@import "xiod-ui/themes/cobalt";67/* ...then change only what you disagree with. */8:root {9 --radius: 0.25rem;10 --primary: #1d4ed8;1112 @variant dark {13 --primary: #93c5fd;14 }15}If you would rather define everything yourself, this is the complete set. Copy it below the import and edit in place — anything you leave out falls back to the library default, so you can also delete the parts you do not care about.
1:root {2 --radius: 0.625rem;34 /* Surfaces */5 --background: #ffffff;6 --foreground: #262626;7 --card: #ffffff;8 --card-foreground: #262626;9 --popover: #ffffff;10 --popover-foreground: #262626;1112 /* Theme */13 --primary: #262626;14 --primary-foreground: #fafafa;15 --secondary: #f5f5f5;16 --secondary-foreground: #262626;17 --muted: #f5f5f5;18 --muted-foreground: #737373;19 --accent: #f5f5f5;20 --accent-foreground: #262626;2122 /* States — the -foreground is text on a TINT of the colour, not on the23 solid fill. Keep it the same hue, just darker. */24 --destructive: #ef4444;25 --destructive-foreground: #b91c1c;26 --info: #3b82f6;27 --info-foreground: #1d4ed8;28 --success: #10b981;29 --success-foreground: #047857;30 --warning: #f59e0b;31 --warning-foreground: #b45309;3233 /* Lines and focus */34 --border: #e5e5e5;35 --input: #d4d4d4;36 --ring: #a3a3a3;3738 /* Sidebar — safe to delete if you do not use it */39 --sidebar: #fafafa;40 --sidebar-foreground: #525252;41 --sidebar-primary: #262626;42 --sidebar-primary-foreground: #fafafa;43 --sidebar-accent: #f5f5f5;44 --sidebar-accent-foreground: #262626;45 --sidebar-border: #ebebeb;46 --sidebar-ring: #a3a3a3;4748 @variant dark {49 /* Every token above, again, with dark-scheme values. Anything you leave50 out here keeps the library's dark default. */51 --background: #0a0a0a;52 --foreground: #f5f5f5;53 /* ... */54 }55}Values can be any CSS colour syntax — hex, oklch(), hsl(), color-mix(). Hex is used here only because it is the easiest to paste from a design tool.
Nothing stops you shipping unreadable colours, so two checks are worth doing by hand — they are the ones every shipped palette is held to.
-foreground against its partner should reach 4.5:1 — --foreground on --background, --primary-foreground on --primary, and so on down the list.--destructive regardless of your tokens, so that colour has to be dark enough for white to read on it — and still distinct enough from --background to look like a control.Any contrast checker will do. The failure to watch for is a --primary that looks great as a large button and becomes unreadable as a small link.
--radius is one length that every component derives its corners from. Set it to 0rem for a square, technical look, or past 1rem for a soft, consumer one — nothing else needs to change.
1:root {2 --radius: 0rem; /* square */3 --radius: 1.25rem; /* or round */4}Tokens obey the cascade like any other CSS property, so an override can be attached to any selector rather than the whole document. Useful for a marketing page that should look louder than the product, or an embedded widget that has to match a host.
1/* An override does not have to be global. Any selector works, because2 tokens cascade like any other CSS property. */34.marketing-site {5 --primary: #db2777;6 --radius: 1.5rem;7}89/* Everything inside is pink and round; the rest of the app is untouched. */This is exactly how the shipped palettes work in their /scoped form — they attach to [data-palette="name"] instead of :root. See the Themes page.
When you want one button to be different rather than every button, do not touch the tokens at all.
1/* For a single element, skip tokens entirely — every component2 forwards className, and your class wins. */34<Button className="bg-emerald-600 text-white hover:bg-emerald-700">5 Publish6</Button>78/* Reach for a token when you want the change everywhere,9 and for className when you want it exactly here. */