Docs · Styling
Theming
Light and dark, plus custom colors, radius and font.
Two layers: light and dark, which everyone gets, and custom themes, which change the brand colors, corner radius and font. Both only change CSS variables, so every component follows without code changes.
Light and dark
The theme is set by data-theme on <html>. People choose light, dark or system; the choice is saved in localStorage.
ThemeProvider(inproviders.tsx) holds the choice.themeScriptruns in<head>before paint, so the page never flashes the wrong theme.ThemeToggleis a sun/moon button;ThemeSwitcheroffers all three choices.
"use client"; import { useTheme } from "@/components/ui/theme-provider"; const { theme, resolvedTheme, setTheme } = useTheme();// theme: "light" | "dark" | "system" resolvedTheme: what's shownsetTheme("dark");// Pass the click point to reveal the new theme in a growing circlesetTheme("dark", { x: event.clientX, y: event.clientY });Custom themes
Try it on the Theme builder. Each color is one value; every shade (hover, pressed, tint, border, text on top) and the whole dark theme are worked out from it, following the Arise UI scale.
- Primary, secondary, accent. The editor warns when a color reads below 4.5:1 in either theme.
- Tint surfaces. Backgrounds, borders and text take a hint of the primary hue.
- Corner radius. Buttons use the value; cards 1.5×, panels 2×, tags ½.
- Font. A Google Fonts link, a font-file link, or an upload kept in the browser.
Ship a theme for everyone
Switch the Theme builder to Code to read the CSS as you edit, or press Copy CSS, and paste it at the end of globals.css. It only contains the variables that differ from Arise UI.
Let each person choose
// src/app/layout.tsx: in <head>, before anything paintsimport { customThemeScript, themeScript } from "@/lib/theme";<script dangerouslySetInnerHTML={{ __html: themeScript + customThemeScript }} /> // src/app/providers.tsx<ThemeProvider> <CustomThemeProvider>{children}</CustomThemeProvider></ThemeProvider> // A settings pageimport { ThemeCustomizer } from "@/components/ui/theme-customizer";<ThemeCustomizer />"use client"; import { useCustomTheme } from "@/components/ui/custom-theme";import { DEFAULT_THEME } from "@/lib/theme"; const { theme, update, set, reset } = useCustomTheme(); update({ primary: "#0b63ce" }); // change some settingsset({ ...DEFAULT_THEME, radius: 12 }); // replace all of themreset(); // back to Arise UIMaking a component themeable
- Use token utilities, never hex colors.
- Derive inner radii from the tokens, e.g.
rounded-[calc(var(--radius-sm)_-_2px)], not a fixed px value. - Read live colors with
getComputedStyleonly when you must (3D does, throughuseThemeColors).