Step-by-step guide to add a new UI theme to AiderDesk (SCSS + CSS variables + types + i18n).
Use this skill when you need to add a new theme to AiderDesk.
AiderDesk themes are implemented as SCSS files that define a .theme-<name> class with a full set of CSS custom properties (variables). The UI uses Tailwind utilities mapped to these CSS variables.
src/renderer/src/themes/theme-<name>.scsssrc/renderer/src/themes/themes.scsspackages/common/src/types/common.ts (THEMES)src/renderer/src/components/settings/GeneralSettings.tsxsrc/renderer/src/App.tsx (applies theme-<name> class to document.body)packages/common/src/locales/en.json (themeOptions.<name>)packages/common/src/locales/zh.json (themeOptions.<name>)Each theme is a class:
.theme-<name>--color-* variables.Best workflow: copy an existing theme (e.g. theme-dark.scss) and adjust values.
Pick a kebab-case name, e.g. sunset, nord, paper.
You will reference it consistently in:
.theme-<name>theme-<name>.scssTHEMES array value: '<name>'themeOptions.<name>Create:
src/renderer/src/themes/theme-<name>.scssStart by copying a similar theme (dark -> dark-ish, light -> light-ish), then update the hex colors.
Minimum requirement: define all variables expected by the app.
Practical way to ensure completeness:
src/renderer/src/themes/theme-dark.scss (or another full theme)Edit:
src/renderer/src/themes/themes.scssAdd:
@use 'theme-<name>.scss';
If the file is not imported here, it wonβt be included in the built CSS.
Edit:
packages/common/src/types/common.tsAdd '<name>' to the exported THEMES array.
This makes the theme selectable and type-safe.
Edit:
packages/common/src/locales/en.jsonpackages/common/src/locales/zh.jsonAdd entries under themeOptions:
{
"themeOptions": {
"<name>": "Your Theme Name"
}
}
Each variable maps from --color-<group>-<variant> in SCSS to a Tailwind utility like bg-<group>-<variant>, text-<group>-<variant>, or border-<group>-<variant>. The mapping is defined in tailwind.config.js.
--color-bg-*)The app uses a 5-tier surface hierarchy from darkest to lightest (for dark themes; reversed for light):
| Variable | Usage | Where visible |
|---|---|---|
bg-primary |
Deepest background β app body, outer containers | body, outer page wrapper, main content areas, inline edit panels |
bg-primary-light |
Primary raised surface β task bars, sidebar items, file viewers, content panels | TaskBar, TaskItem (idle), file viewer scrollable area, top-bar gradient end |
bg-primary-light-strong |
Semi-transparent overlay β selected items, diff/file headers, notifications, tooltip arrows, reflected messages | TaskItem (selected), PierreDiffViewer header, toast notification bg |
bg-secondary |
Card/panel surface β input fields, dialog content, chips, selected/hovered task items | Model dialog, chip items, settings cards, hover on menu items |
bg-secondary-light |
Elevated input container β search/dropdown wrappers, dropdown menus, merge button popover | Tag input containers, settings dropdown focus wrappers |
bg-secondary-light-strongest |
Opaque elevated surface β dialogs (BaseDialog), thinking blocks, inactive tab hover | BaseDialog bg, ThinkingAnswerBlock, inactive project tab hover |
bg-tertiary |
Hover/highlight surface β icon button hover, menu item hover, scrollbar thumb, diff gutter omit, CodeMirror autocomplete border | All icon button hovers, menu item hovers, scrollbar thumbs |
bg-tertiary-emphasis |
Accent-tinted hover β uses the theme's accent color at ~25% opacity for tinted hover states | Header icon button hover, delete button hover backgrounds, task badges |
bg-tertiary-strong |
Stronger tinted hover β accent color at ~50% opacity | Active project tab hover |
bg-fourth |
Separator / small control surface β vertical dividers in TaskBar, checkbox checked state, close button bg, tab hover for active tab | TaskBar dividers, Checkbox checked bg, BaseDialog close button |
bg-fourth-muted |
Accent-tinted subtle bg β accent color at ~20% opacity | Decorative/special accent backgrounds |
bg-fourth-emphasis |
Accent-tinted medium bg β accent color at ~30% opacity | Decorative/special accent backgrounds |
bg-fifth |
Highest hover state β used for "close" button hover in dialogs | BaseDialog close button hover |
bg-selection |
Text selection highlight β used in PromptField for text selection color | PromptField ::selection color |
bg-code-block |
Code block background β standalone code blocks, diff file items, log viewer | CodeBlock component, DiffFileItem, LogsPage pre blocks |
--color-bg-diff-viewer-*)| Variable | Usage |
|---|---|
diff-viewer-old-primary |
Deleted line background (used in DiffViewer.scss, CompactDiffViewer) |
diff-viewer-old-secondary |
Deleted line character-level edit highlight |
diff-viewer-new-primary |
Inserted line background |
diff-viewer-new-secondary |
Inserted line character-level edit highlight |
--color-text-*)| Variable | Usage | Visible on |
|---|---|---|
text-primary |
Primary text β labels, headings, button text, body text | Most text throughout the app |
text-secondary |
Secondary text β icons in header, model subtitles, status text | Header icons (notebook, chart, settings), model provider text |
text-tertiary |
Tertiary text β hover state for muted items, diff modified markers, toolbar button hover | Hover state text, diff line numbers, expanded toolbar buttons |
text-muted-light |
Dimmed text β reflected messages, placeholder labels | ReflectedMessageBlock, disabled-state labels |
text-muted |
Muted text β description paragraphs, log viewer text, empty states | Settings descriptions, log output, chip empty labels |
text-muted-dark |
Dark muted β input placeholders, section dividers | PromptField placeholder, TaskSectionHeader |
text-dark |
Darkest text β very deep background text, decorative | Rarely used, deepest layer text |
--color-border-*)| Variable | Usage | Visible on |
|---|---|---|
border-dark |
Subtlest border β outer container edges, sticky headers | Home page outer border, UpdatedFilesDiffModal header, bash blocks |
border-dark-light |
Light subtle border β code blocks, sidebar section separators, task item borders | CodeBlock border, TaskSectionHeader top border, TaskItem border |
border-dark-light-strong |
Semi-transparent subtle border β reflected messages, code block <hr> |
ReflectedMessageBlock, CodeBlock horizontal rules |
border-default-dark |
Medium border β prompt input borders (unfocused), diff comment panel | PromptField unfocused border |
border-default |
Standard border β inputs, cards, dividers, containers (most common) | Settings inputs, Home container, inline edit panels, TaskItem |
border-accent |
Accent border β focused inputs, checked checkboxes/radios, diff headers, badge borders | PromptField focus, Checkbox checked, PierreDiffViewer header |
border-light |
Lightest border β selected/focused inputs, active tab indicators | Settings active option border, input focus state |
--color-accent-*)| Variable | Usage |
|---|---|
accent-primary |
Brand accent β AI sparkle icon, welcome message bullets, commit badges, voice recording indicator |
accent-secondary |
Secondary accent β selected answer highlights, decorative accents |
accent-light |
Highlight accent β token usage bar fill, hover text for commit links |
--color-success-*, --color-warning-*, --color-error-*, --color-info-*)Each has up to 7 variants with consistent suffix semantics:
--color-button-*)Three button palettes (primary, secondary, danger) each with 5 variants. See Button.tsx for the full mapping:
| Variant | Usage in contained |
Usage in text |
Usage in outline |
|---|---|---|---|
(base) |
Background | β | Border color |
-light |
Hover background | β | β |
-subtle |
β | Hover background | Hover background |
-emphasis |
Hover background (danger) | β | β |
-text |
Text color | Text color | Text color |
The tertiary button color uses bg-primary/bg-secondary + text-primary instead of dedicated button tokens.
Disabled buttons use: bg-bg-tertiary-strong background + text-text-muted text.
--color-input-*)Currently not directly used in TSX components β inputs use bg-bg-secondary + border-border-default + text-text-primary instead. These are defined for potential future use or custom components.
--color-agent-*)Semantic colors for tool/badge indicators in the AgentSelector and related UI:
agent-auto-approve β auto-approve toggle indicatoragent-aider-tools β aider tools iconagent-power-tools β power tools iconagent-todo-tools β todo tool badgeagent-tasks-tools β tasks tool badgeagent-memory-tools β memory tool badgeagent-skills-tools β skills tool badgeagent-subagents-tools β subagents tool badgeagent-context-files β context file indicatoragent-repo-map β repo map indicatoragent-ai-request β AI request indicatoragent-sub-agent β sub-agent indicatorDark themes (those that need a dark code editor) must also be added to the isCodeEditorDarkTheme array in packages/common/src/types/common.ts.
Many variables include an inline hex alpha suffix (e.g. #D4A05440 = accent at ~25% opacity). The convention is:
1a β 10% β subtle19 β 10% β subtle (alternate)26 β 15% β muted33 β 20% β muted4c β 30% β emphasis4d β 30% β emphasis (alternate)50 β 31% β selection60 β 38% β strong7f β 50% β strong (alternate)80 β 50% β semi-transparentf2 β 95% β almost opaqueSome components use CSS variables directly via var(--color-*) instead of Tailwind utilities:
main.css: body background/text, CodeMirror editor styling, resize handleDiffViewer.scss / PierreDiffViewer.scss: diff line backgrounds, guttersnotifications.ts: toast background/text stylingPromptField.tsx: text selection colorTheme not showing up:
@use import in src/renderer/src/themes/themes.scssTHEMES array in packages/common/src/types/common.ts.theme-<name> and the <name> stored in settingsSome UI areas look "unstyled":
--color-* variables; compare against a known-good theme and fill in the missing ones.Input fields don't match theme:
bg-bg-secondary + border-border-default for inputs, not the input-* tokens. Focus on the bg/border/text hierarchies instead.