Logotipo Hedhog

Get Hedhog updates in your inbox

New releases, fresh recipes, and breaking changes — no spam.

Theming

Hedhog's admin panel is fully customizable through settings — colors, logo, favicon, app name, and typography — with no rebuild required. This is one of the most completely implemented recipes in Hedhog: every setting below is real, wired into apps/admin/src/components/provider/theme-provider.tsx, and takes effect immediately.

In the admin, all of this lives under Settings → Configurations → Appearance — there is no group literally named "Theme," even though every setting key below is prefixed theme-.

Status: ✅ Fully implemented — every setting below is real and takes effect on the next page load.

Light and dark admin dashboard mockups with their independent color settings mapped to CSS variables

Quick Setup

  1. Go to Settings → Configurations → Appearance
  2. Set theme-primary-light and theme-primary-dark (and the other color pairs) to your brand's hex colors
  3. Upload your logo/favicon via File Storage, then paste the resulting URLs into image-url/icon-url
  4. Hard-refresh the admin and confirm the new colors and logo actually render

How It Works

  1. Theme settings are stored as rows in the setting table, under the Appearance configuration group
  2. On load, the admin's ThemeProvider reads them (cached in localStorage under the settings key) and injects a <style> block straight into the document — each color setting becomes a CSS custom property like --primary, written as !important so it overrides Tailwind's defaults
  3. Colors are applied as raw hex strings, not converted to HSL — if a value isn't a valid #rrggbb string, that rule is silently skipped and the Tailwind default shows through instead
  4. Hedhog tracks light and dark variants of every color independently — there is no single source color that gets auto-darkened; you set both explicitly
  5. theme-mode controls light/dark/system, and a per-user override is stored client-side in localStorage under theme — so an individual user can flip to dark mode without changing the system default for everyone else

Color Settings

Every color below exists twice — once with a -light suffix and once with a -dark suffix — under Settings → Configurations → Appearance. Hedhog does not generate one from the other; if you only set the light variant, dark mode falls back to Tailwind's defaults for that token.

CSS variableLight setting keyDark setting keyWhat it controls
--primarytheme-primary-lighttheme-primary-darkButtons, links, active states, focus rings
--primary-foregroundtheme-primary-foreground-lighttheme-primary-foreground-darkText/icons on primary-colored backgrounds
--secondarytheme-secondary-lighttheme-secondary-darkSecondary buttons, subtle accents
--secondary-foregroundtheme-secondary-foreground-lighttheme-secondary-foreground-darkText on secondary backgrounds
--accenttheme-accent-lighttheme-accent-darkHover/interactive accents
--accent-foregroundtheme-accent-foreground-lighttheme-accent-foreground-darkText on accent backgrounds
--mutedtheme-muted-lighttheme-muted-darkDisabled states, subtle backgrounds
--muted-foregroundtheme-muted-foreground-lighttheme-muted-foreground-darkSecondary/dimmed text
--backgroundtheme-background-lighttheme-background-darkPage background
--background-foregroundtheme-background-foreground-lighttheme-background-foreground-darkDefault body text
--cardtheme-card-lighttheme-card-darkCard/panel surfaces
--card-foregroundtheme-card-foreground-lighttheme-card-foreground-darkText on cards

All values must be 6-digit hex (#1e40af), no alpha channel. --primary-light is also reused for --bprogress-color (the top-of-page loading bar), so your brand color shows up there too without a separate setting.

Mode & Typography

Setting keyDescription
theme-modeSystem default: light, dark, or system. Individual users can override this locally without changing it for anyone else
theme-radiusBorder radius in rem applied via CSS variable, affects buttons/cards/inputs globally
theme-fontCSS font-family stack (default ui-sans-serif, system-ui, sans-serif)
theme-text-sizeGlobal text scale factor

Branding

Setting keyDescription
image-urlLogo shown in the admin shell
icon-urlFavicon
system-nameApplication name shown in the browser title and sidebar
system-sloganTagline shown alongside the name
menu-widthSidebar width in rem

These are consumed directly by the admin shell/layout components rather than ThemeProvider's CSS-injection logic — uploading new files for image-url/icon-url works the same way as any other file upload (see File Storage): upload first, then paste the resulting URL into the setting.

Applying Changes

Saving any setting in Settings → Configurations → Appearance takes effect on the next page load for that browser, since ThemeProvider reads from localStorage-cached settings and re-applies them via a useEffect on mount, not via a live socket push. If a teammate doesn't see your change, tell them to hard-refresh rather than assuming the setting didn't save.


Verify It Worked

  • Hard-refresh the admin after saving a color and confirm the new color actually renders — not just that the setting saved successfully
  • Toggle dark mode and confirm the -dark variants show up too, instead of falling back to Tailwind's defaults

Troubleshooting

SymptomLikely cause
A color setting has no visible effectValue isn't a valid #rrggbb hex string — the rule is silently dropped, not an error
Dark mode looks unbranded even though light mode is styled correctlyYou only set the -light variant of that color — set its -dark counterpart explicitly
User can't get out of a stuck dark/light preferenceTheir local override lives in localStorage under theme (and theme-source) on their own browser — clearing site data resets it to the system default
Logo/favicon doesn't update after uploading a new fileThe setting still points at the old file's URL — re-paste the new uploaded URL into image-url/icon-url