Kawa
Styling

Fonts

Load custom fonts from files, classpath resources, or Google Fonts. Apply CSS-style numeric weights to any element.

By default Kawa uses Helvetica — a standard PDF font that does not need to be embedded. For custom typography, create a KawaFont and apply it to any element.

Font weights

Kawa uses a CSS-style numeric weight scale. Named shortcuts cover the most common values:

MethodWeightCSS equivalent
.light()300light
.regular()400normal
.medium()500medium
.semiBold()600semi-bold
.bold()700bold
.weight(int)customany value 100–900
c.text("Light heading").light().fontSize(14);
c.text("Normal body").fontSize(11);
c.text("Emphasis").semiBold();
c.text("Strong").bold();
c.text("Extra heavy").weight(800);

The italic axis is independent — combine it with any weight:

c.text("Italic semi-bold").semiBold().italic();

Loading fonts

Google Fonts

The easiest option — Kawa downloads and caches the font automatically:

KawaFont lato = KawaFont.fromGoogle("Lato");

On first use Kawa fetches the available variants from Google Fonts and saves them to ~/.kawa/fonts/. Subsequent calls load from that cache.

KawaFont.fromGoogle() needs a network connection on first use. In offline or CI environments, load fonts from files or classpath resources.

Classpath resources

Bundle the font files inside your JAR and load them by weight:

// Single file — all weights fall back to regular
KawaFont inter = KawaFont.ofResource("/fonts/Inter-Regular.ttf");

// Builder — register each weight you have
KawaFont inter = KawaFont.builder()
    .weight(400, FontSource.resource("/fonts/Inter-Regular.ttf"))
    .weight(600, FontSource.resource("/fonts/Inter-SemiBold.ttf"))
    .weight(700, FontSource.resource("/fonts/Inter-Bold.ttf"))
    .weightItalic(400, FontSource.resource("/fonts/Inter-Italic.ttf"))
    .build();

Named builder shortcuts map directly to weights:

KawaFont inter = KawaFont.builder()
    .regularResource("/fonts/Inter-Regular.ttf")
    .semiBold(new ResourceFontSource("/fonts/Inter-SemiBold.ttf"))
    .boldResource("/fonts/Inter-Bold.ttf")
    .italicResource("/fonts/Inter-Italic.ttf")
    .build();

File system

KawaFont custom = KawaFont.builder()
    .weight(400, "/usr/share/fonts/Custom-Regular.ttf")
    .weight(700, "/usr/share/fonts/Custom-Bold.ttf")
    .build();

Weight resolution

When you request a weight that is not explicitly registered, Kawa picks the nearest registered weight. With the two-file setup below, .semiBold() (600) resolves to the bold file (700) since that is closest:

KawaFont f = KawaFont.builder()
    .weight(400, "/fonts/Inter-Regular.ttf")
    .weight(700, "/fonts/Inter-Bold.ttf")
    .build();

c.text("Nearest bold").font(f).semiBold();   // resolves to 700
c.text("Nearest regular").font(f).medium();  // resolves to 400

If no italic sources are registered, Kawa falls back to the nearest upright source.

Applying fonts to elements

c.text("Heading").font(inter).semiBold().fontSize(16);
c.text("Subheading").font(inter).medium().fontSize(12);
c.text("Body").font(inter).fontSize(11);
c.text("Caption").font(inter).light().italic().fontSize(9);

TextElement, RichTextElement.Span, and HyperlinkElement all support the same weight and italic API.

Fallback

If a font fails to load for any reason, Kawa falls back to Helvetica and logs a warning. The document still renders; only the typeface changes.

On this page