Fonts

#Default fonts

Every app starts with a UI font and a monospace font from the theme:

RoleFamilySize
UI text.SystemUIFont16px
Code / monospacemacOS: Menlo, Windows: Consolas, Linux: DejaVu Sans Mono13px

The editor paints its code in mono_font_family at mono_font_size. See Editor for details.

#System fonts

Desktop apps can use any font installed on the OS by name — no bundling, no config. GPUI resolves the family live against the system collection (CoreText on macOS, DirectWrite on Windows, fontconfig on Linux).

div().font_family("Segoe UI")

Editor::new(&editor).font_family("JetBrains Mono")

Common examples per platform:

  • macOS: SF Pro, Helvetica, Arial, Times New Roman, Menlo, Monaco
  • Windows: Segoe UI, Arial, Consolas, Courier New
  • Linux: Noto Sans, DejaVu Sans, Liberation Sans, DejaVu Sans Mono

If the name does not match an installed font, GPUI falls back silently — so verify the exact family name on each target platform.

#Changing fonts via Theme

Set the app-wide fonts on the Theme global, then sync to the base layer:

Theme::global_mut(cx).font_family = "Inter".into();
Theme::global_mut(cx).mono_font_family = "JetBrains Mono".into();
Theme::global_mut(cx).font_size = px(18.);
Theme::sync_base(cx);
window.refresh();

font_size doubles as the application zoom control — Root calls window.set_rem_size(cx.theme().font_size), so rem-based spacing scales with it. See Coding Guides for details.

#Per-element override

Any element accepts a font override without touching the theme:

div()
    .font_family("JetBrains Mono")
    .text_size(px(15.))
    .font_weight(FontWeight::BOLD)

These are ordinary Styled methods, so they compose with the rest of the style chain.

#Bundling custom fonts

Fonts that are not installed on the user’s system must be bundled and registered with the text system before the first frame:

cx.text_system()
    .add_fonts(vec![Cow::Borrowed(
        include_bytes!("../fonts/MyFont-Regular.ttf").as_slice(),
    )])
    .expect("Failed to load fonts");

Then reference them by family name as usual:

Theme::global_mut(cx).font_family = "MyFont".into();
Theme::sync_base(cx);

The gallery’s web build bundles Inter, JetBrains Mono, NotoSansSC and NotoEmoji this way — see crates/story-web/src/lib.rs.

#Theme JSON config

Font families and sizes can also come from a theme file:

{
    "font.family": "Inter",
    "font.size": 16,
    "mono_font.family": "JetBrains Mono",
    "mono_font.size": 13
}

Load it with ThemeRegistry:

ThemeRegistry::watch_dir(PathBuf::from("./themes"), cx, move |cx| {
    if let Some(theme) = ThemeRegistry::global(cx).themes().get(&theme_name).cloned() {
        Theme::global_mut(cx).apply_config(&theme);
    }
});

See Theme for the full config reference.

#WebAssembly note

Browsers expose no system fonts to WASM apps. The story-web gallery (which runs at gpui-kit.com/gallery/) must bundle every family it uses and re-assert them after Theme::change, or the text system panics. Desktop apps skip this entirely.

CC BY 4.0 · Documentation prose and original illustrations GPUI Kit has rights to license may be copied or adapted with attribution. License. Credit GPUI Kit, link to this source page and the CC BY 4.0 license, and indicate any changes. Code examples and software source remain under Apache-2.0. Existing Apache permissions remain; third-party material retains its own terms.