Typography#

bootstack uses a token-based font system. Every widget that accepts a font= argument takes a token string such as "body" or "heading-lg". Tokens resolve to named fonts at startup and update automatically when the theme changes, so you style text by role rather than by hard-coding families and sizes. A small set of functions adjusts those tokens at runtime.

Platform defaults#

bootstack picks native UI and monospace families for each platform so an app looks at home on every desktop, and tunes the base point size so text appears the same visual size everywhere:

Platform

UI family

Monospace family

Base size

Windows

Segoe UI

Cascadia Mono

11 pt

macOS

SF Pro Text

Menlo

13 pt

Linux / other

DejaVu Sans

DejaVu Sans Mono

11 pt

The macOS base is two points larger because Tk converts points to pixels against a 72 DPI baseline there — versus roughly 96 DPI on Windows and Linux — which would otherwise render the same point size noticeably smaller. The bump keeps text at visual parity across platforms and aligns with the macOS control-text size.

Override the family with set_font_family() (see Setting the application font family); if a requested family is not installed, bootstack keeps the current fonts rather than falling back silently.

Font tokens#

All sizes shown are relative to the base size for the platform (see Platform defaults). The actual pixel size also varies with DPI scaling.

Token

Approx size

Weight

Typical use

display-xl

base+17

bold

Hero headings, splash screens

display-lg

base+11

bold

Page titles, large callouts

heading-xl

base+7

bold

Section headings

heading-lg

base+4

bold

Sub-section headings

heading-md

base+2

bold

Card titles, dialog headers

heading-sm

base+1

bold

Group labels, compact headings

body-lg

base+1

normal

Emphasized body text

body

base

normal

Default widget text

body-sm

base-1

normal

Secondary text, hints

caption

base-2

normal

Timestamps, metadata, fine print

label

base-2

bold

Form labels, table headers

code

base (mono)

normal

Code, paths, identifiers

hyperlink

base

normal

Inline links (underlined)

Modifiers#

Append bracket modifiers to any token. Multiple modifiers can be chained. Heading tokens are already bold — adding [bold] is a no-op.

Modifier

Effect

[bold]

Bold weight

[italic]

Italic slant

[underline]

Underlined text

[overstrike]

Strikethrough

[+N]

Increase size by N points relative to the token base

[-N]

Decrease size by N points relative to the token base

[N]

Set absolute size to N points

[Npx]

Set absolute size to N pixels (negative points in Tk)

bs.Label("Italic caption",    font="caption[italic]")
bs.Label("Underlined body",   font="body[underline]")
bs.Label("Slightly larger",   font="body[+2]")
bs.Label("Slightly smaller",  font="body[-1]")
bs.Label("Bold italic body",  font="body[bold][italic]")
bs.Label("Heading italic",    font="heading-md[italic]")

Size delta#

[+N] and [-N] shift the size relative to the token’s own base, not the global base size. body[+2] is always 2 pt larger than body, regardless of theme or DPI scaling.

Use absolute sizes ([14]) only when you need a specific measurement independent of the token scale — for example, matching an external design spec.

Setting the application font family#

set_font_family switches every text token to one family in a single call. The monospace code token keeps its own family so code stays readable; pass mono_family= to change it too:

from bootstack.style import set_font_family

import bootstack as bs

with bs.App() as app:
    set_font_family("Inter")                       # body, headings, labels…
    set_font_family("Inter", mono_family="Fira Code")
app.run()

If the requested family is not installed, a warning is issued and the current fonts are left unchanged — text never silently falls back to an unexpected face.

Adjusting a font token#

update_font_token overrides individual attributes of a single token. Only the attributes you pass change; the rest are left as is. The update applies everywhere the token is used:

from bootstack.style import update_font_token

update_font_token("body", size=12)              # larger default text
update_font_token("code", family="JetBrains Mono")
update_font_token("caption", slant="italic")

Listing installed families#

get_font_families returns the installed UI families, sorted and filtered of system and emoji fonts — ready to populate a font picker or to validate input before calling set_font_family:

from bootstack.style import get_font_families

with bs.App() as app:
    families = get_font_families()
    bs.Select(options=families, signal=bs.Signal(families[0]))
app.run()

Choosing a font interactively#

ask_font opens a font selector and returns the user’s choice as a FontChoice — a plain namedtuple with family, size, weight, slant, underline, and overstrike fields (or None if canceled):

choice = bs.ask_font(default_font="body")
if choice:
    update_font_token("body", family=choice.family, size=choice.size)

See also#

  • Theming — colors, accents, and custom themes.

  • Font Dialog — the ask_font() / FontDialog selector.

  • Label — the primary widget for displaying text with font tokens.

API reference#

The complete reference for the runtime font functions lives in Theming (alongside the theme functions). At a glance:

set_font_family

Set the application font family for all non-code text.

update_font_token

Override the attributes of a single font token.

get_font_families

Return the installed UI font families available to the application.

The FontChoice result type returned by ask_font() is documented with the Font Dialog selector.