Skip to main content

Fonts Guide

XFrames pre-renders fonts into a GPU texture atlas at startup. You declare which fonts and sizes you need in fontDefs, then reference them in style rules with font: { name, size }.

Defining fonts

The fontDefs object lists every font/size combination to load. Each name maps to a .ttf file in assets/fonts/ — for example, "roboto-regular" loads assets/fonts/roboto-regular.ttf.

const fontDefs = {
defs: [
{ name: "roboto-regular", sizes: [16, 18, 20, 24, 32] },
{ name: "roboto-bold", sizes: [16, 20, 24] },
]
.map(({ name, sizes }) => sizes.map((size) => ({ name, size })))
.flat(),
};

The .map().flat() pattern expands { name, sizes: [16, 20] } into [{ name, size: 16 }, { name, size: 20 }], which is the format the native layer expects.

Pass fontDefs as the third argument to render():

render(App, assetsBasePath, fontDefs, theme);

Available font files

These fonts ship with create-xframes-node-app in assets/fonts/:

FileDescription
roboto-regular.ttfDefault sans-serif
roboto-bold.ttfBold weight
roboto-light.ttfLight weight
roboto-mono-regular.ttfMonospace

To use a custom font, drop its .ttf file into assets/fonts/ and add it to fontDefs with the filename (without extension) as the name.

Using fonts in styles

Set the font on any widget via the font property in a style rule. Both name and size must match an entry in your fontDefs:

import { RWStyleSheet } from "@xframes/common";

const styles = RWStyleSheet.create({
heading: {
font: { name: "roboto-bold", size: 32 },
padding: { bottom: 8 },
},
body: {
font: { name: "roboto-regular", size: 16 },
},
code: {
font: { name: "roboto-mono-regular", size: 14 },
},
});
const App = () => (
<XFrames.Node root style={{ height: "100%" }}>
<XFrames.UnformattedText style={styles.heading} text="Dashboard" />
<XFrames.UnformattedText style={styles.body} text="Welcome to the app." />
</XFrames.Node>
);
warning

If you reference a font name or size that isn't in fontDefs, the widget will fall back to the default font. Always ensure your style rules match what you declared.

Font Awesome icons

Font Awesome 6 Solid is automatically merged into every loaded font — no extra setup needed. You can render any icon by placing its Unicode character in a text prop.

Using the icon map

Import faIconMap from @xframes/common to look up icons by name:

import { faIconMap } from "@xframes/common";

const App = () => (
<XFrames.Node root style={{ height: "100%" }}>
<XFrames.UnformattedText text={`${faIconMap["check"]} Connected`} />
<XFrames.UnformattedText text={`${faIconMap["triangle-exclamation"]} Warning`} />
<XFrames.UnformattedText text={`${faIconMap["gear"]} Settings`} />
</XFrames.Node>
);

Using Unicode escapes directly

If you know the codepoint, use a Unicode escape:

<XFrames.UnformattedText text={"\uf00c Done"} />   {/* check */}
<XFrames.UnformattedText text={"\uf0e7 Fast"} /> {/* bolt */}

Browse available icons at fontawesome.com/icons. The icon names in faIconMap match Font Awesome's naming convention (e.g. "arrow-right", "circle-info", "house").

Icons in Table columns

Table boolean columns render check and xmark icons automatically — no manual icon handling needed. Set type: "boolean" on the column definition and the Table widget handles the rest.

Tips

  • Only declared sizes are available. If you need size 28, add it to fontDefs — there's no interpolation.
  • More sizes = more GPU memory. Each font/size combination adds a glyph atlas entry. Declare only what you need.
  • Icons scale with font size. Font Awesome glyphs are rendered at 2/3 of the text font size for visual alignment.
  • 16-bit glyph range only. Icons in the U+E005–U+F8FF range are supported. Material Design Icons (which require 32-bit glyphs) are not currently available.

Next steps

  • Layout guide — flexbox basics, scroll containers, and nested layouts
  • Styling guide — colors, backgrounds, and interaction states