macbetter

Foundations

Typography

macbetter uses Apple's text styles, from Large Title to Caption. Each is a single token that changes with the platform, so a headline is 13px on macOS and 17px on iPhone without you writing either number.

Text styles

Pick a platform in the preview. The size, line height, weight and tracking under each name are read from the page as it renders.

Large Title 

Library

Title 1 

Recently Added

Title 2 

Shared with You

Title 3 

Albums

Headline 

Morning Run

Body 

Your playlist syncs to every device.

Callout 

Downloads finish in the background.

Subheadline 

Updated 2 minutes ago

Footnote 

Requires macOS 15 or later.

Caption 

42 songs, 2 hr 18 min

The full ramp, in px (size/line height):

StylemacOSiPadOS and iOSWeight
Large Title26/3234/41Semibold on macOS, bold on touch
Title 122/2628/34Semibold on macOS, bold on touch
Title 217/2222/28Semibold on macOS, bold on touch
Title 315/2020/25Semibold
Headline13/1617/22Semibold
Body13/1617/22Regular
Callout12/1516/21Regular
Subheadline11/1415/20Regular
Footnote10/1313/18Regular
Caption10/1312/16Regular

Tracking is set per group. On macOS, large titles are −0.022em, titles −0.016em, body −0.003em and captions +0.006em. On iPadOS and iOS, large titles are −0.021em, titles −0.018em, body −0.025em and captions 0.

Using the styles

Each style is a class that sets font and letter-spacing together:

<h1 className="mb-text-large-title">Library</h1>
<p className="mb-text-body mb-label-secondary">Your playlists sync to every device.</p>

The classes are mb-text-large-title, mb-text-title-1, mb-text-title-2, mb-text-title-3, mb-text-headline, mb-text-body, mb-text-callout, mb-text-subheadline, mb-text-footnote and mb-text-caption. Two more change only the family: mb-text-mono and mb-text-rounded.

In your own CSS, use the tokens. --mb-text-* is a full font shorthand, and the tracking is separate:

.inspector-title {
  font: var(--mb-text-headline);
  letter-spacing: var(--mb-tracking-body);
}
Tracking tokenUsed with
--mb-tracking-large-titleLarge Title
--mb-tracking-titleTitle 1 to 3
--mb-tracking-bodyHeadline to Subheadline
--mb-tracking-captionFootnote and Caption

Controls have their own font tokens, --mb-control-font, --mb-control-font-sm and --mb-control-font-lg: 13px medium on macOS and 17px medium on touch for the default size.

The body style is the default. [data-macbetter] and every [data-platform] element set font: var(--mb-text-body), so plain text inside picks up the platform's size.

Fonts

Four seed tokens hold the families:

TokenDefault
--mb-font-apple-system, BlinkMacSystemFont, SF Pro Text, SF Pro Display, system-ui, Inter, Helvetica Neue, Segoe UI
--mb-font-displayvar(--mb-font)
--mb-font-roundedui-rounded, SF Pro Rounded, then --mb-font
--mb-font-monoui-monospace, SF Mono, Geist Mono, Menlo, Consolas

On Apple devices the stack resolves to San Francisco, which switches between its Text and Display cuts by size on its own. Elsewhere it falls back to the system UI font.

Titles use --mb-font-display, from Title 3 up on iPadOS and iOS and from Title 2 up on macOS. Set it to a different family to give headings a voice without changing body text.

Change the fonts

Set the seeds in a theme. Load the font yourself, then name it first in the stack:

[data-theme="harbor"] {
  --mb-font: "Inter", system-ui, sans-serif;
  --mb-font-display: "Inter Display", "Inter", system-ui, sans-serif;
}

Or with createTheme(), using the font, fontDisplay and fontMono options. The text style tokens are computed where data-platform is set, so a font change takes effect on that element and below. If you change fonts on a nested element, add data-platform to it as well; see Theming.

Pick a font with a large x-height and open shapes at small sizes. macOS body text is 13px, and a display face that looks fine at 34px may not hold up there.

Size and legibility

macbetter doesn't implement Dynamic Type: the text styles are fixed pixel sizes per platform, and they don't follow the iOS text size setting. Browser zoom scales everything, and the layout tokens scale with it.

To keep text readable when people zoom or enlarge text:

  • Use text styles, not pixel sizes. Then the hierarchy stays consistent and one change of token moves everything.
  • Let rows grow. Use min-height: var(--mb-row-height) rather than height, so a row with wrapped or enlarged text gets taller instead of clipping.
  • Don't truncate what people need. Wrap labels in forms and settings; truncate only where the full text is available elsewhere, like a file name with a details view.
  • Keep the hierarchy small. Most screens need a title, body and one secondary style. Use weight and label color for emphasis before size.