Theming

Harmo's colors, type, and shapes are --harmo-* custom properties. The quickest way to change its color is an accent. For your own brand color, generate a theme. Any token can also be set by hand.

Try it

Pick an accent or your own color, corners, and a font. The color applies to this whole site, as it would to your app; corners and font show in every component's examples. Both stay until you reset them.

Color
Corners
8px
Font
Language
  • English
  • Spanish
  • Arabic
Plan

Weekly summary

An email with last week's conversations.

Notifications

Sounds and badges for new messages.

These are Harmo's defaults. Pick a color, corners, or a font above, and what to add to your app shows here.

Accents

data-harmo-accent recolors everything inside it, in light and dark mode: text and links in the primary, checked marks and their tints, buttons, switches, and the focus ring.

index.html
<html lang="en" data-harmo-accent="blue">

In a React app, that's the <html> of your root layout.

The accents are purple (the default), blue, teal, green, amber, red, pink, and mono, which is black, or near-white in dark mode, with dark text on its buttons there and links underlined on hover. Each has the same contrast as the purple in every role, so text, and the text on buttons, pass WCAG AA in both modes.

Put the attribute on any element to recolor only that part of the page. An accent inside another has its own colors throughout:

index.html
<section data-harmo-accent="mono">
  <!-- Black buttons and links here, whatever the page's accent -->
</section>

index.css includes accents.css, and npx harmo-ui add copies it with tokens.css; with per-component imports, load accents.css after tokens.css.

Your brand color

bunx harmo-ui theme "#0f75b6"

That writes harmo-theme.css: your color in every role, in light and dark mode, adapted from the nearest accent at the same contrast, so text and buttons pass WCAG AA. A color too light for white text, such as a bright yellow, is darkened for text and buttons, and the file says so. In a project with a harmo.css from npx harmo-ui add, it's added there. See the CLI.

It's ordinary CSS: change any line you like, since your values win over Harmo's wherever the file loads. Without the CLI, pick your color in the editor above, which shows the same CSS to copy.

Tokens

Token names say what is colored, then the variant, then the state, as in --harmo-color-primary-hover. --harmo-color-* names are semantic roles; plain names such as --harmo-purple are the palette they default to, so you can re-theme by changing roles without touching components.

Font

The font is the system's by default. To match an existing app, set it once:

globals.css
:root {
  --harmo-font-family: "Helvetica Neue", Helvetica, sans-serif;
}

Your overrides win

Token defaults are declared on :where(:root), and accents with :where() too, so your overrides on :root win whichever stylesheet loads last, over an accent on <html> as well. An accent on a section sets its colors on that section, which win inside it over what it inherits from :root: to change one, override it on the section.

Local themes

For a local theme, override the role on the component or a containing element instead of :root. Tokens built from another token are worked out on :root, so a local override doesn't reach them: redeclare those in the same place.

globals.css
.dark-panel {
  --harmo-color-focus: #8ab4ff;
  --harmo-focus-outline: 2px solid var(--harmo-color-focus);
}

The built tokens are --harmo-focus-outline, the primary fills, the link, input, switch, icon, and secondary-button tokens, and the button and chevron durations. See all the tokens.

Dark mode

Harmo's colors come in light and dark pairs, through CSS's light-dark(). A page stays light until it opts in with color-scheme, even on a dark system:

globals.css
:root { color-scheme: dark; }        /* always dark */
:root { color-scheme: light dark; }  /* follows the system */
.sidebar { color-scheme: dark; }     /* one part of the page */

Every accent, and every theme harmo-ui theme writes, covers both modes. To set colors by hand for both, give each as a pair, such as light-dark(#0f75b6, #30aed9). Button and Switch use the --harmo-color-primary-fill tokens rather than the primary: a dark-mode primary light enough to read as text on a dark page is too light to sit behind white text.