Skip to main content

Fonts and text

Family resolution​

A React Native fontFamily can be a single name or, through libraries like NativeWind, a CSS-style stack: "Inter, Helvetica, sans-serif". The engine's ResolveFontFamily function turns that stack into the one family name Impeller receives: it picks the first entry that resolves and maps the generic names (monospace, serif, sans-serif, system-ui, and the ui-* family) to a concrete face for the current OS. Both text measurement and paint call the same function, so they can't disagree about which face a string resolves to.

Fallback for glyphs the primary face doesn't have​

Impeller's font collection doesn't fall back when the primary face is missing a glyph. Without help, emoji, CJK, and Arabic text paint as tofu boxes instead of the right glyph.

On Linux, the engine works around this itself: text is split into runs by which face covers each codepoint, fontconfig is asked for a face that covers the run, and that face is registered with Impeller for that run only. Measurement and paint both go through this splitter, so a multi-script string lays out consistently.

On macOS and Windows, this isn't needed. CoreText and the native Windows text stack provide font fallback without help, so the splitter returns the whole string as a single segment there.

Add fonts on Linux​

Impeller's resolver can see fonts outside the system catalog if you point it at a directory, with --font-dir or the RNI_FONT_DIRS environment variable. That's how a Linux build picks up app-bundled fonts rather than only what's already installed on the host.

A caveat on tabular figures​

The nw:tabularNums utility, NativeWind's class for font-variant: tabular-nums, isn't implemented in the style layer yet. The react-native-css library emits no fontVariant for it, and Apple's faces use proportional digits by default, so the visible effect differs by backend today. This is tracked as a known gap, not a silent miss. See Supported components and style props for the rest of what's covered and what isn't.

Why the Linux text gates pin a specific font​

Text with no fontFamily set gets Impeller's default face, which on Linux is the first installed font from a fixed list: Ubuntu, Cantarell, DejaVu Sans, Liberation Sans, then Arial. That lookup doesn't go through fontconfig. The style-audit gates were measured with the Ubuntu font installed as that default. Without it, Linux falls through to DejaVu Sans: every text tile gets wider, and several gates (underline, line-through, justify, head ellipsis, and tabular figures) move under their thresholds. Fonts referenced by name still resolve normally through fontconfig either way. Only an unset fontFamily value is affected.