Pantrix UI

Typography

Pantrix's type scale, what text given no style is set in, and the size of what is typed into a text field.

1. The scale

PantrixTypography holds nine roles. Sizes and line heights are in sp, and grow with the system's text size.

RoleSize / lineWeightIts job
display36 / 42BoldA page's title
headline28 / 34BoldA section's title
title22 / 28SemiBoldThe title of a card, a panel, a dialog
callout18 / 26MediumText that stands out
body16 / 24MediumA paragraph; what is typed into a text field on Android and iOS
label14 / 20MediumA control's label; what is typed into a text field on the desktop and the web; the base text
footnote12 / 16MediumSupporting text, an error's explanation
caption11 / 14MediumA timestamp, a counter
code14 / 20Medium, monospaceAn identifier, a piece of code

2. Naming it by its role: TypeRole

A component's style holds no typeface; it only says which role it is set in. The typeface is the theme's:

val style: TextStyle = PantrixTheme.typography[TypeRole.Body]

TypeRole has a value for each role (Display … Code). Where a style's TypeRole? field is left empty, the preset's holds.

3. The base text: LocalPantrixTextStyle

The style of text given no style. PantrixText, PantrixLink and PantrixAutoText take it when they are given no style.

ProvidePantrixTextStyle(PantrixTheme.typography.body) {
    PantrixText("The paragraphs of this section are set in body.")
    ProvidePantrixTextStyle(TextStyle(fontWeight = FontWeight.SemiBold)) {
        PantrixText("Only the weight changes; the size stays body's.")
    }
}

Compose foundation's BasicText does not read this value

A BasicText given no style is set in TextStyle.Default: the system's typeface, 14sp. Material's LocalTextStyle, too, is read by Material's own components alone. An app's own BasicText has to take the base text itself:

BasicText(text = words, style = LocalPantrixTextStyle.current)

The library itself has no BasicText without a style (searched on 2026-10-18): all of its text goes through PantrixText.

4. The size of what is typed into a text field

A text field's style says which role it types in with textRole: TextFieldStyle.textRole and FilledTextFieldStyle.textRole.

PlatformRoleSize
AndroidBody16sp
iOSBody16sp
DesktopLabel14sp
WebLabel14sp

What is set in that role:

The label above the box (the label role) and the supporting text (footnote) do not change.

Compared with Material 3

PartMaterial 3Pantrix
What is typedbodyLarge (16/24, Regular)Android and iOS: body (16/24, Medium); desktop and web: label (14/20, Medium)
PlaceholderbodyLargethe same as what is typed
The label insidebodyLarge at rest, bodySmall (12/16) once risenfrom the role of what is typed to footnote (12/16)
Supporting textbodySmallfootnote

In Material 3 these come with OutlinedTextFieldTokens.InputFont = BodyLarge; MaterialTheme also gives LocalTextStyle bodyLarge. Pantrix's label matches Material 3's labelLarge (14/20, Medium), but M3 uses that for the text of buttons and tabs.

Changing it for the whole app

PantrixTheme(
    styles = pantrixStyles(
        TextFieldStyle.override(all = TextFieldStyle(textRole = TypeRole.Body)),
        FilledTextFieldStyle.override(all = FilledTextFieldStyle(textRole = TypeRole.Body))
    )
) { App() }

For a single field, PantrixTextField(style = TextFieldStyle(textRole = TypeRole.Callout)) is enough.

5. Pitfalls

6. Files

FileWhat is in it
ui/foundation/.../token/typography/PantrixTypography.ktThe scale, buildPantrixTypography, rememberPantrixTypography
ui/foundation/.../token/typography/TypeRole.ktTypeRole, PantrixTypography[role]
ui/foundation/.../token/typography/PantrixTextStyle.ktLocalPantrixTextStyle, ProvidePantrixTextStyle
ui/components/.../inputs/textfield/TextFieldStyle.kttextRole and its presets
ui/components/.../inputs/filledtextfield/FilledTextFieldStyle.kttextRole and its presets
app/shared/.../samples/TypographySamples.ktThe demo: "The base text of a part"