Accent colors
View on GitHubAccent colors
The accent color is the one brand color used for buttons, links,
selected states, and highlights across the whole interface — chosen
once per user (Account settings → Preferences → Accent color) and
applied everywhere via three CSS variables:
--accent-color/--accent-light-color/--accent-color-opacity. It's
independent of dark/light theme (the same
accent applies in both, just with a slightly different opacity) and,
non-obviously, shares its entire color-name vocabulary with a
project's badge color — the ten names a user can pick as their
accent are exactly the ten colors available when creating a project,
reused on purpose ("the same palette available when creating a
project," per the Settings UI copy itself) but represented completely
differently under the hood for each use. This category documents that
whole system and the trap that comes with it.
Guides, in the order you'd actually need them
- Add a new accent color —
worked example adding an 11th option,
teal: every one of the four places a color name has to be added, in the right order, and why skipping any one of them produces a different kind of visible breakage. - Use the accent color in a component — the three variables, when to reach for which, and how this differs from a project's own fixed badge color even though both ultimately come from the same ten names.
The architecture in one paragraph
AccentColor (resources/js/types/Accent.ts) is 'default' | ProjectColors — literally reusing ProjectColors
(resources/js/types/Projects.ts), the same ten-value union a
project's color field uses. AccentProvider
(resources/js/context/AccentContext.tsx) holds exactly one piece of
state, the chosen AccentColor, persisted to localStorage; on every
change (and every theme change, since the opacity differs per theme)
it computes CSS variable overrides via
getAccentCssVariables() (resources/js/utils/accentColors.ts) and
writes them as inline styles on <html>
(root.style.setProperty('--accent-color', ...)) — a different
mechanism from theme colors, which live entirely in a static CSS file
keyed by [data-theme]. Picking 'default' removes the inline
overrides entirely, falling back to the plain --accent-color value
global.css already defines per theme (#8844da in both). Picking
any other name looks up a separate hex-value map,
PROJECT_ACCENT_HEX, keyed by the same ten names a project's badge
color renders from getColorTheme()
(resources/js/utils/colors.ts) — but that second map is built from
literal Tailwind utility classes (bg-red-500, …), not hex codes, so
the two features never actually share code, only the list of valid
names. There's a third independent copy of the hex map besides —
a plain-JS duplicate inline in resources/views/app.blade.php's
pre-paint <script>, needed because that script runs before any JS
bundle (and therefore accentColors.ts) is even loaded. That's the
trap guide 1 walks through in full.
