Skip to content
Crow CI

Appearance and theme overrides

The Appearance section of your user settings controls how the Crow UI looks in your browser. All appearance settings are stored in the browser’s local storage, so they apply per browser and are not synced to your account.

Crow ships several built-in themes, and the instance admin can add more (listed under Instance themes). You can pick one theme for light mode and another for dark mode, and choose whether the color mode follows your system or is fixed to light or dark.

Theme overrides let you change individual colors of the selected themes without writing a whole theme. They use the CSS custom property format of shadcn/ui, so output from theme generators such as tweakcn can be pasted as is.

  1. Open your user settings and scroll to Appearance > Theme Overrides.

  2. Enter CSS variables, or click Insert current theme to start from the full variable set of your selected themes.

  3. Check the summary below the editor, which lists how many variables will be applied and anything that is ignored.

  4. Click Apply to store the overrides and restyle the UI.

Variables in a :root block override the light theme, variables in a .dark block override the dark theme:

:root {
  --primary: #7c3aed;
  --sidebar: #ede9fe;
}

.dark {
  --primary: #a78bfa;
}

The overrides are layered on top of whichever theme is selected, so switching themes keeps them in effect. To remove all overrides, clear the editor and click Apply.

  • Light mode blocks: :root, html, .light and [data-theme="light"].
  • Dark mode blocks: .dark, :root.dark, html.dark and [data-theme="dark"].
  • Comments, !important and wrapping @layer blocks are allowed.
  • Values must be valid CSS colors, for example #7c3aed, rgb(124 58 237) or oklch(0.54 0.25 293).

Other selectors (for example the @theme inline block tweakcn emits), properties that are not theme variables (such as --radius or --font-sans) and invalid colors are ignored and listed below the editor.

VariableUsed for
--background, --foregroundPage background and default text
--card, --card-foregroundCards and panels
--popover, --popover-foregroundDropdowns, menus and tooltips
--primary, --primary-foregroundPrimary buttons and highlights
--secondary, --secondary-foregroundSecondary buttons
--muted, --muted-foregroundSubtle backgrounds and secondary text
--accent, --accent-foregroundHover and selection states
--destructive, --destructive-foregroundDestructive actions and errors
--border, --input, --ringBorders, input borders and focus rings
--chart-1 to --chart-5Metrics charts
--sidebar, --sidebar-foregroundSidebar background and text
--sidebar-primary, --sidebar-primary-foregroundActive sidebar items
--sidebar-accent, --sidebar-accent-foregroundHovered sidebar items
--sidebar-border, --sidebar-ringSidebar borders and focus rings

Instance admins can add their own themes, or restyle a bundled one, with CROW_CUSTOM_THEMES. The variable takes a comma-separated list of sources, each a file path or an http(s):// URL:

CROW_CUSTOM_THEMES=/etc/crow/themes.json,https://example.com/themes/acme-corp.css

Each source is either CSS or JSON, detected from its content.

A CSS source defines one theme, in the same format as theme overrides: a :root block for light mode and a .dark block for dark mode.

/* acme-corp.css */
:root {
  --primary: #7c3aed;
  --sidebar-primary: #7c3aed;
}

.dark {
  --primary: #a78bfa;
}

The id and name come from the file name: acme-corp.css becomes the theme acme-corp, shown as “Acme Corp”. A leading theme- is dropped, so theme-acme-corp.css gives the same result. The theme inherits unset colors from crow-ci, or from the bundled theme of the same name, which it then replaces.

A JSON source holds an array of themes, a single theme, or a shadcn/tweakcn registry item such as https://tweakcn.com/r/themes/<name>.json:

[
  {
    "id": "acme",
    "name": "ACME Corp",
    "description": "ACME corporate colors",
    "base": "crow-ci",
    "light": {
      "primary": "#7c3aed",
      "sidebar-primary": "#7c3aed"
    },
    "dark": {
      "primary": "#a78bfa"
    }
  }
]
FieldRequiredDescription
idyes¹Unique identifier, lowercase letters, digits, - and _. Stored in the user’s browser on selection.
namenoName shown in the theme selection. Defaults to the id.
descriptionnoShort description of the theme.
basenoId of a bundled theme to take unset variables from. Defaults to crow-ci.
lightnoLight mode colors, keyed by variable name with or without the leading --.
darknoDark mode colors, in the same format as light.
cssVarsnoAlternative to light and dark: the cssVars object of a shadcn/tweakcn registry theme.

¹ Without an id, a name made only of id characters is used as id, as in registry items, which are shown under their title. Otherwise a source with a single theme takes its id from the file name, as for CSS.

  • A theme must define at least one theme color. Other variables, such as fonts or --radius in tweakcn output, are ignored.
  • Theme ids must be unique across all sources.
  • To restyle a bundled theme for everyone, use its id, for example crow-ci for the default theme. The theme then inherits from the bundled version, so only the changed colors need to be listed.
  • The bundled theme ids are crow-ci, catppuccin, claude, doom-64, modern-minimal, mono, ocean-breeze, t3-chat and vercel.
  • Each source may be at most 1 MiB.

Sources are read once at startup, so restart the server after changing one. If a file cannot be read or a source is invalid, the server refuses to start and logs the reason. If a URL cannot be fetched (network error, timeout after 10 seconds, or a status other than 200), the server logs an error and starts without the themes from that URL.