macbetter

Foundations

Color

Use semantic tokens, not raw colors. A token like --mb-label-secondary says what a color is for, and it stays right in light and dark, in every theme.

The Ember palette

The default theme, Ember, pairs warm oranges with deep greens. Orange carries action; Racing Green is the stage. The ratio on each swatch is its best contrast against white or Racing Green.

5.0:1
Trinidad#EE5700Accent and orange, light
6.7:1
Gold Drop#F67F01Accent and orange, dark
7.9:1
Neon Carrot#F9943CAccent text, dark
9.7:1
Rajah#F8B16DBrand art, not a token
17.7:1
Racing Green#0A1C13Ink, on-accent, dark background
7.3:1
Stromboli#25604EBrand art, not a token
4.4:1
Observatory#028F71Secondary accent and green, light
7.5:1
Emerald#44BD8BGreen, dark
8.4:1
Puerto Rico#52C6A0Secondary accent and mint, dark

Rajah and Stromboli belong to the brand but aren't used by any token. Use them in illustration and marketing, not in controls.

Semantic tokens

These swatches read the live CSS variables, so they follow the theme and scheme you pick in the header. Use the preview's sun and moon button to see the other scheme.

Labels
Aa
--mb-labelPrimary text
Aa
--mb-label-secondarySubtitles, values
Aa
--mb-label-tertiaryPlaceholders, hints
Aa
--mb-label-quaternaryDisabled text
Aa
--mb-accent-textLinks, tinted text
Aa
--mb-destructive-textDestructive text
Backgrounds
--mb-bgWindow and page
--mb-bg-secondaryGrouped page
--mb-bg-tertiaryInset groups
--mb-bg-elevatedPopovers, sheets
--mb-bg-sidebarSidebars
--mb-bg-controlBezeled controls
--mb-bg-fieldText fields
Fills
--mb-fillSwitch track, touch press
--mb-fill-secondaryTouch bezeled buttons
--mb-fill-tertiaryHover, segmented track
--mb-fill-quaternaryQuiet hover, large areas
Separators
--mb-separatorBetween rows
--mb-separator-strongSection edges
--mb-separator-opaqueOpaque hairlines
--mb-control-borderControl edges, 3:1
Accent
--mb-accentFilled controls
--mb-accent-hoverPointer hover
--mb-accent-pressedPress
--mb-accent-softTinted fills
--mb-on-accentText on accent
--mb-accent-secondarySecond brand color
--mb-focus-ringFocus halo
--mb-selectionText selection
System palette
--mb-redRed
--mb-orangeOrange
--mb-yellowYellow
--mb-greenGreen
--mb-mintMint
--mb-tealTeal
--mb-cyanCyan
--mb-blueBlue
--mb-indigoIndigo
--mb-purplePurple
--mb-pinkPink
--mb-brownBrown

Labels

Four levels of text, from --mb-label down to --mb-label-quaternary. They're all --mb-ink at decreasing opacity, so they sit correctly on any background, including materials.

  • Label for primary text.
  • Secondary for subtitles and supporting values.
  • Tertiary for placeholders and hints.
  • Quaternary for disabled text. It's deliberately below 4.5:1, so don't use it for anything a person needs to read.

--mb-accent-text is the accent adjusted to read as text. Use it for links and text-only buttons, never --mb-accent itself, which may be too light on a white background.

Classes mb-label, mb-label-secondary, mb-label-tertiary and mb-label-accent apply the most common ones.

Backgrounds

--mb-bg is the page. --mb-bg-secondary and --mb-bg-tertiary form the grouped hierarchy of iOS settings screens: a secondary page with tertiary groups on it. --mb-bg-elevated is for surfaces that float, --mb-bg-sidebar for source lists, and --mb-bg-control and --mb-bg-field for bezeled controls and text fields.

Fills

Four translucent grays mixed from --mb-tint, from --mb-fill (strongest) to --mb-fill-quaternary. They tint whatever is behind them, so use them for shapes that sit on varying backgrounds: switch tracks, segmented control tracks, hover and pressed states.

Separators

--mb-separator divides rows and --mb-separator-strong marks larger edges. Both are translucent; --mb-separator-opaque is the same color mixed onto the background, for when overlapping translucent lines would show darker spots. --mb-control-border is for the edges of controls, and is derived to hold 3:1 against the background. --mb-hairline is the 0.5px width they're usually drawn at.

Accent

--mb-accent fills the one primary action in a view. --mb-accent-hover and --mb-accent-pressed are derived lighter and darker in OKLCH, --mb-accent-soft is a 16% tint of it, the strength tinted buttons use, and --mb-focus-ring and --mb-selection are translucent mixes for the focus halo and selected text. Text on the accent uses --mb-on-accent.

--mb-destructive, --mb-success and --mb-warning point at red, green and yellow.

System palette

Twelve colors named as in the HIG, from --mb-red to --mb-brown. Use them for status, categories and charts. The Ember theme replaces orange, green and mint with brand colors; the System theme uses Apple's values.

Using color

  • Reach for the role, not the hue. Write var(--mb-label-secondary), not a gray. Write var(--mb-destructive), not var(--mb-red), when you mean "this deletes something".
  • One accent per view. The accent means "this is the action". If everything is orange, nothing is.
  • Never rely on color alone. Pair status colors with an icon or text, so the meaning survives color blindness and grayscale.
  • Derive, don't hard-code. For a shade that doesn't exist, mix from a token: color-mix(in oklch, var(--mb-accent) 24%, transparent) or oklch(from var(--mb-accent) calc(l - 0.05) c h). It then follows the theme and scheme.

Contrast

macbetter's targets are WCAG's: text at 4.5:1 against its background, and control edges, focus rings and state fills at 3:1, in light and dark. Under prefers-contrast: more, secondary and tertiary labels, separators and control borders get stronger, and materials turn opaque.

On a white background, Trinidad as text reaches only 3.5:1, which is why the theme uses a darker orange, #B84300, for --mb-accent-text in light mode. Text on the orange accent is Racing Green, not white, for the same reason. Accessibility has the ratios for every built-in theme.