> ## Documentation Index
> Fetch the complete documentation index at: https://docs.formepdf.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom Fonts

> Register custom TrueType fonts for PDF embedding with automatic subsetting.

Forme includes three standard PDF font families by default: **Helvetica**, **Times**, and **Courier** (each with regular, bold, italic, and bold italic variants), plus **Noto Sans** (regular and bold) as a builtin Unicode fallback for non-Latin scripts. For any other typeface, register a TrueType (`.ttf`) font file.

Registered fonts are automatically subsetted — only glyphs used in the document are embedded, keeping file sizes small.

## Font.register()

Register fonts globally. Works like react-pdf's `Font.register()`.

```tsx theme={null}
import { Font } from '@formepdf/react';

Font.register({
  family: 'Inter',
  src: './fonts/Inter-Regular.ttf',
});

Font.register({
  family: 'Inter',
  src: './fonts/Inter-Bold.ttf',
  fontWeight: 'bold',
});

Font.register({
  family: 'Inter',
  src: './fonts/Inter-Italic.ttf',
  fontStyle: 'italic',
});
```

Then use the font by name in any style:

```tsx theme={null}
<Text style={{ fontFamily: 'Inter', fontSize: 14 }}>
  Regular text in Inter
</Text>
<Text style={{ fontFamily: 'Inter', fontSize: 14, fontWeight: 'bold' }}>
  Bold text in Inter
</Text>
```

### Options

| Option       | Type                                | Default    | Description                                           |
| ------------ | ----------------------------------- | ---------- | ----------------------------------------------------- |
| `family`     | `string`                            | (required) | Font family name to reference in `fontFamily` style   |
| `src`        | `string \| Uint8Array`              | (required) | Font source: file path, base64 data URI, or raw bytes |
| `fontWeight` | `number \| "normal" \| "bold"`      | `400`      | Font weight. `"normal"` = 400, `"bold"` = 700.        |
| `fontStyle`  | `"normal" \| "italic" \| "oblique"` | `"normal"` | Font style variant                                    |

### Font.clear()

Remove all globally registered fonts. Useful in tests.

```tsx theme={null}
Font.clear();
```

### Multiple weights in one call

You can register multiple weights for the same family using the `fonts` array syntax:

```tsx theme={null}
Font.register({
  family: 'Inter',
  fonts: [
    { src: './fonts/Inter-Regular.ttf', fontWeight: 400 },
    { src: './fonts/Inter-Bold.ttf', fontWeight: 700 },
    { src: './fonts/Inter-Italic.ttf', fontWeight: 400, fontStyle: 'italic' },
  ],
});
```

## Google Fonts

You can register fonts directly from a URL. Google Fonts `.woff2` URLs work:

```tsx theme={null}
import { Font, Document, Page, Text } from '@formepdf/react';

Font.register({
  family: 'Inter',
  fonts: [
    { src: 'https://fonts.gstatic.com/s/inter/v13/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuLyfAZ9hiA.woff2', fontWeight: 400 },
    { src: 'https://fonts.gstatic.com/s/inter/v13/UcCO3FwrK3iLTeHuS_fvQtMwCp50KnMw2boKoduKmMEVuI6fAZ9hiA.woff2', fontWeight: 700 },
  ],
});

export default function Doc(data) {
  return (
    <Document>
      <Page>
        <Text style={{ fontFamily: 'Inter', fontWeight: 700, fontSize: 24 }}>Bold heading</Text>
        <Text style={{ fontFamily: 'Inter', fontSize: 12 }}>Regular body text</Text>
      </Page>
    </Document>
  );
}
```

<Tip>
  To find the direct `.woff2` URL for a Google Font, open `https://fonts.googleapis.com/css2?family=Inter:wght@400;700` in your browser and copy the `url()` value from the CSS.
</Tip>

## Font fallback chains

Specify multiple font families separated by commas. Forme tries each family in order per character, so mixed-script text (e.g., English + Arabic) works automatically:

```tsx theme={null}
<Text style={{ fontFamily: 'Inter, Noto Sans' }}>
  English text and عربي in the same paragraph
</Text>
```

If a character isn't covered by `Inter`, Forme tries `Noto Sans`. If no font in the chain covers the character, the builtin Noto Sans is used as a final fallback.

## Document fonts prop

Register fonts per-document instead of globally:

```tsx theme={null}
<Document fonts={[
  { family: 'Roboto', src: './fonts/Roboto-Regular.ttf' },
  { family: 'Roboto', src: './fonts/Roboto-Bold.ttf', fontWeight: 'bold' },
  { family: 'Roboto', src: './fonts/Roboto-Italic.ttf', fontStyle: 'italic' },
]}>
  <Text style={{ fontFamily: 'Roboto' }}>Hello in Roboto</Text>
</Document>
```

Document fonts and global fonts are merged. If both register the same family + weight + style combination, the document font wins.

## Font sources

The `src` option accepts three formats:

| Format       | Example                          | When to use                         |
| ------------ | -------------------------------- | ----------------------------------- |
| File path    | `'./fonts/Inter.ttf'`            | Local development, CLI dev server   |
| Data URI     | `'data:font/ttf;base64,AAAA...'` | Pre-encoded fonts, bundled assets   |
| `Uint8Array` | `new Uint8Array(buffer)`         | Fonts loaded from a database or API |

File paths are resolved relative to the template file in the CLI dev server (`forme dev`), or relative to the working directory in `renderDocument()`.

## Standard fonts

These fonts are always available without registration:

| Family      | Weights  | Styles         | Notes                    |
| ----------- | -------- | -------------- | ------------------------ |
| `Helvetica` | 400, 700 | normal, italic | Default font             |
| `Times`     | 400, 700 | normal, italic |                          |
| `Courier`   | 400, 700 | normal, italic |                          |
| `Noto Sans` | 400, 700 | normal         | Builtin Unicode fallback |

**Automatic fallback**: When a character is not covered by your chosen font (e.g., Cyrillic or Greek text with Helvetica), Forme automatically falls back to Noto Sans. This means non-Latin text works out of the box without registering any fonts.

If a `fontFamily` is not found, Forme falls back to Helvetica.

## Example: Multiple weights

```tsx theme={null}
import { Font, Document, Page, View, Text } from '@formepdf/react';
import { renderDocument } from '@formepdf/core';

Font.register({ family: 'Inter', src: './fonts/Inter-Regular.ttf' });
Font.register({ family: 'Inter', src: './fonts/Inter-Medium.ttf', fontWeight: 500 });
Font.register({ family: 'Inter', src: './fonts/Inter-SemiBold.ttf', fontWeight: 600 });
Font.register({ family: 'Inter', src: './fonts/Inter-Bold.ttf', fontWeight: 700 });

const pdf = await renderDocument(
  <Document>
    <Page size="A4" margin={54}>
      <Text style={{ fontFamily: 'Inter', fontWeight: 400 }}>Regular (400)</Text>
      <Text style={{ fontFamily: 'Inter', fontWeight: 500 }}>Medium (500)</Text>
      <Text style={{ fontFamily: 'Inter', fontWeight: 600 }}>SemiBold (600)</Text>
      <Text style={{ fontFamily: 'Inter', fontWeight: 700 }}>Bold (700)</Text>
    </Page>
  </Document>
);
```

## Troubleshooting

### Text renders in Helvetica instead of my custom font

The `fontFamily` in your style must exactly match the `family` you passed to `Font.register()`. Font names are case-sensitive.

```tsx theme={null}
// Registration
Font.register({ family: 'Inter', src: './fonts/Inter-Regular.ttf' });

// ✅ Correct
<Text style={{ fontFamily: 'Inter' }}>Works</Text>

// ❌ Wrong — case mismatch
<Text style={{ fontFamily: 'inter' }}>Falls back to Helvetica</Text>
```

### Bold or italic text falls back to Helvetica

You need to register each weight and style variant separately. If you register only the regular weight and use `fontWeight: 700`, Forme will look for a bold variant, not find one, and fall back.

```tsx theme={null}
// Only regular registered — bold will fall back
Font.register({ family: 'Inter', src: './fonts/Inter-Regular.ttf' });

// Fix: register the bold variant too
Font.register({ family: 'Inter', src: './fonts/Inter-Bold.ttf', fontWeight: 700 });
```

### Non-Latin characters show as boxes or question marks

The font you're using doesn't cover those characters. Either:

1. Register a font that covers them (e.g., Noto Sans for broad Unicode support)
2. Use a [font fallback chain](#font-fallback-chains): `fontFamily: 'Inter, Noto Sans'`
3. Do nothing — Forme's builtin Noto Sans provides automatic fallback for most scripts
