Skip to content

Theming

Lattice renders with a small set of semantic design tokens — CSS custom properties prefixed with --lt-. Every token resolves through a host variable with a built-in fallback, so you can theme Lattice by defining the host variables (the same names shadcn/ui uses) on :root and .dark. For example, set --primary and Lattice’s --lt-primary follows.

Tokens are global and shared across components. The Style tab on each component example lists the tokens that example uses in its initial rendered state. Tokens that only appear in interactive or overlay content — a dropdown panel, a dialog, a popover that opens on demand — are not captured there; this page is the complete reference.

Every token ships a light and a dark value (the Light and Dark columns below). Dark mode is driven by a dark class on the <html> element: when it is present, the .dark host variables take over and Lattice’s tokens follow. You theme dark mode the same way as light — by defining the host variables under .dark.

Lattice manages the class for you through its appearance helpers, exported from the package:

  • initializeTheme() — call once before your app mounts (e.g. in your entry file). It reads the stored preference (localStorage key appearance, default system), applies the dark class and color-scheme, and keeps them in sync when the OS preference changes.
  • useAppearance() — a hook returning { appearance, resolvedAppearance, updateAppearance }. appearance is the chosen mode ("light" | "dark" | "system"), resolvedAppearance is the effective "light" | "dark" after resolving system, and updateAppearance(mode) persists the choice (to localStorage and a cookie) and applies it immediately. Build your own theme switcher on top of it.
import { initializeTheme, useAppearance } from "@lattice-php/lattice";
initializeTheme();
function AppearanceToggle() {
const { appearance, updateAppearance } = useAppearance();
return (
<button onClick={() => updateAppearance(appearance === "dark" ? "light" : "dark")}>
Toggle theme
</button>
);
}

Colors

Token Host variable Light Dark
--lt-bg --background oklch(0.97 0 0) oklch(0.145 0 0)
--lt-fg --foreground oklch(0.145 0 0) oklch(0.985 0 0)
--lt-surface --card oklch(1 0 0) oklch(0.145 0 0)
--lt-surface-fg --card-foreground oklch(0.145 0 0) oklch(0.985 0 0)
--lt-popover --popover oklch(1 0 0) oklch(0.145 0 0)
--lt-popover-fg --popover-foreground oklch(0.145 0 0) oklch(0.985 0 0)
--lt-primary --primary oklch(0.48 0.092 182) oklch(0.74 0.105 182)
--lt-primary-fg --primary-foreground oklch(0.985 0 0) oklch(0.2 0.025 182)
--lt-secondary --secondary oklch(0.97 0 0) oklch(0.269 0 0)
--lt-secondary-fg --secondary-foreground oklch(0.205 0 0) oklch(0.985 0 0)
--lt-muted --muted oklch(0.97 0 0) oklch(0.269 0 0)
--lt-muted-fg --muted-foreground oklch(0.556 0 0) oklch(0.708 0 0)
--lt-accent --accent oklch(0.965 0.013 182) oklch(0.278 0.018 182)
--lt-accent-fg --accent-foreground oklch(0.4 0.07 182) oklch(0.985 0 0)
--lt-danger --destructive oklch(0.585 0.21 27.3) oklch(0.42 0.13 26)
--lt-danger-fg --destructive-foreground oklch(0.985 0 0) oklch(0.985 0 0)
--lt-border --border oklch(0.922 0 0) oklch(0.269 0 0)
--lt-input --input oklch(0.922 0 0) oklch(0.269 0 0)
--lt-ring --ring oklch(0.72 0.075 182) oklch(0.55 0.08 182)
--lt-overlay --overlay oklch(0 0 0 / 0.5) oklch(0 0 0 / 0.6)
--lt-warning --warning oklch(0.84 0.14 88) oklch(0.7 0.13 78)
--lt-success --success oklch(0.62 0.125 160) oklch(0.7 0.15 162)
--lt-success-fg --success-foreground oklch(0.985 0 0) oklch(0.205 0 0)
--lt-info --info oklch(0.62 0.14 240) oklch(0.7 0.14 240)
--lt-info-fg --info-foreground oklch(0.985 0 0) oklch(0.205 0 0)
--lt-primary-hover --primary-hover oklch(0.43 0.092 182) oklch(0.79 0.105 182)
--lt-primary-active --primary-active oklch(0.39 0.092 182) oklch(0.84 0.105 182)
--lt-danger-hover --destructive-hover oklch(0.53 0.21 27.3) oklch(0.47 0.13 26)
--lt-danger-active --destructive-active oklch(0.48 0.21 27.3) oklch(0.52 0.13 26)
--lt-success-hover --success-hover oklch(0.57 0.125 160) oklch(0.75 0.15 162)
--lt-success-active --success-active oklch(0.52 0.125 160) oklch(0.8 0.15 162)
--lt-info-hover --info-hover oklch(0.57 0.14 240) oklch(0.75 0.14 240)
--lt-info-active --info-active oklch(0.52 0.14 240) oklch(0.8 0.14 240)
--lt-secondary-hover --secondary-hover oklch(0.93 0 0) oklch(0.32 0 0)
--lt-secondary-active --secondary-active oklch(0.9 0 0) oklch(0.36 0 0)
--lt-disabled --disabled oklch(0.95 0 0) oklch(0.32 0 0)
--lt-disabled-fg --disabled-foreground oklch(0.7 0 0) oklch(0.55 0 0)
--lt-icon-xs 0.75rem 0.75rem
--lt-icon-sm 0.875rem 0.875rem
--lt-icon-md 1rem 1rem
--lt-icon-lg 1.25rem 1.25rem
--lt-icon-xl 1.5rem 1.5rem
--lt-icon-2xl 2rem 2rem
--lt-icon-3xl 2.5rem 2.5rem
--lt-icon-4xl 3rem 3rem
--lt-icon-stroke 1.5 1.5
--lt-control-h-sm 2rem 2rem
--lt-control-h-md 2.25rem 2.25rem
--lt-control-h-lg 2.5rem 2.5rem
--lt-table-cell-x calc(var(--spacing) * 4) calc(var(--spacing) * 4)
--lt-table-cell-y calc(var(--spacing) * 4) calc(var(--spacing) * 4)
--lt-font-weight-normal 400 400
--lt-font-weight-medium 500 500
--lt-font-weight-semibold 600 600
--lt-font-weight-bold 700 700
--lt-shadow-xs 0 1px 1px 0 oklch(0 0 0 / 0.04) 0 1px 1px 0 oklch(0 0 0 / 0.04)
--lt-shadow-sm 0 1px 2px 0 oklch(0 0 0 / 0.05) 0 1px 2px 0 oklch(0 0 0 / 0.05)
--lt-shadow-md 0 2px 4px -1px oklch(0 0 0 / 0.08), 0 1px 2px -1px oklch(0 0 0 / 0.06) 0 2px 4px -1px oklch(0 0 0 / 0.08), 0 1px 2px -1px oklch(0 0 0 / 0.06)
--lt-shadow-lg 0 8px 16px -4px oklch(0 0 0 / 0.12), 0 2px 4px -2px oklch(0 0 0 / 0.08) 0 8px 16px -4px oklch(0 0 0 / 0.12), 0 2px 4px -2px oklch(0 0 0 / 0.08)
--lt-z-dropdown 1000 1000
--lt-z-sticky 1100 1100
--lt-z-overlay 1200 1200
--lt-z-modal 1300 1300
--lt-z-popover 1400 1400
--lt-z-toast 1500 1500
--lt-duration-fast 120ms 120ms
--lt-duration-base 160ms 160ms
--lt-sidebar-w 16rem 16rem
--lt-sidebar-w-collapsed 4rem 4rem
--lt-container-max 80rem 80rem
--lt-gutter calc(var(--spacing) * 6) calc(var(--spacing) * 6)

Radius

Token Host variable Light Dark
--lt-radius --radius 0.5rem 0.5rem
--lt-radius-sm calc(var(--lt-radius) - 0.125rem) calc(var(--lt-radius) - 0.125rem)
--lt-radius-xs calc(var(--lt-radius) - 0.25rem) calc(var(--lt-radius) - 0.25rem)