Fonts
Text the engine writes, in a free text box, a form field or a redaction label, is in the font its
fontFamily names. Register fontsPlugin() to list the fonts a document can be written in, and to
draw text in a browser in the very font the engine will write it with:
<script lang="ts">
import { useFontsState } from '@embedpdf/svelte/fonts';
let { value = $bindable() }: { value: string } = $props();
const fontsState = useFontsState();
const choosable = $derived(fontsState.fonts?.fonts.filter((font) => font.canChoose) ?? []);
</script>
<select bind:value>
{#each choosable as font (font.name)}
<option value={font.name}>{font.name}</option>
{/each}
</select>The annotation and form layers use the plugin by themselves: with it, text being typed shows in the fonts the engine writes it with; without it, in the standard font the engine falls back to. Nothing is read when a document opens: the fonts are read the first time something asks for them.
The fonts you can use#
fonts has
every font, with where it comes from:
source | The fonts |
|---|---|
'standard' | The 14 standard PDF fonts, drawn the same everywhere. They only cover Latin text. |
'engine' | The engine’s own fonts: the ones you register locally, your server’s on the cloud. |
'document' | The fonts the PDF already has. |
A font’s name is what fontFamily takes. canChoose says whether new text can be written in it,
and when it can’t, restrictions says why:
| Restriction | Why |
|---|---|
'subset' | The PDF holds only the characters its text uses. |
'not-embedded' | The PDF only names the font. |
'preview-and-print' | Its licence allows showing and printing, not editing. |
'unsupported-format' | A Type 1, CFF or Type 3 font: new text is written in TrueType or OpenType. |
'no-unicode-map' | The font doesn’t say which character each of its letters is. |
'not-served' | A server font whose file stays on the server. It can still be chosen. |
A box keeps the font it has either way. Every field of a font is on the engine’s Fonts page.
The list keeps up by itself. A write that puts a font in the document, such as Hebrew typed in a box, which the engine fills in from a Hebrew font, reads it again:
Loading live preview…
<script lang="ts" module>
import { DocumentGate, Viewer, type OpenInput } from '@embedpdf/svelte/runtime';
import { interactionPlugin } from '@embedpdf/svelte/interaction';
import { annotationPlugin } from '@embedpdf/svelte/annotation';
import { fontsPlugin } from '@embedpdf/svelte/fonts';
import { localEngine } from '@embedpdf/engine';
import Fonts from './Fonts.svelte';
import '../list.css';
const engine = localEngine();
const plugins = [interactionPlugin(), annotationPlugin(), fontsPlugin()];
const welcome = async (): Promise<OpenInput> => {
const response = await fetch('/pdfs/welcome.pdf');
return { kind: 'bytes', id: 'welcome', bytes: new Uint8Array(await response.arrayBuffer()) };
};
</script>
<Viewer {engine} {plugins} initialDocuments={[{ source: welcome }]}>
<DocumentGate>
{#snippet fallback()}
<p class="loading">Loading…</p>
{/snippet}
<Fonts />
</DocumentGate>
</Viewer>Draw text in a font#
useFontCss(font)
gives the CSS a font is drawn with, and mounts its programs (the font files) while your component
lives:
<script lang="ts">
import { useFontCss } from '@embedpdf/svelte/fonts';
let { font }: { font: string } = $props();
// Its programs are mounted while this component lives.
const css = useFontCss(() => font);
</script>
<input
value="Hello שלום"
style:font-family={css.current?.fontFamily}
style:font-weight={css.current?.fontWeight}
style:font-style={css.current?.fontStyle}
style:font-synthesis="none"
/>Draw with font-synthesis: none, so the browser never fakes a bold or an italic the engine won’t
draw. The CSS names the engine’s own programs, then the same fallback fonts the engine fills
missing characters from, in its order, then a font that draws a character no font has as a box,
as the engine writes it. Until the browser has every program, it names the system’s closest fonts
instead, and the CSS changes when they arrive.
Loading live preview…
<script lang="ts" module>
import { DocumentGate, Viewer, type OpenInput } from '@embedpdf/svelte/runtime';
import { fontsPlugin } from '@embedpdf/svelte/fonts';
import { localEngine } from '@embedpdf/engine';
import FontPreview from './FontPreview.svelte';
import '../draw.css';
const engine = localEngine();
const plugins = [fontsPlugin()];
const welcome = async (): Promise<OpenInput> => {
const response = await fetch('/pdfs/welcome.pdf');
return { kind: 'bytes', id: 'welcome', bytes: new Uint8Array(await response.arrayBuffer()) };
};
</script>
<Viewer {engine} {plugins} initialDocuments={[{ source: welcome }]}>
<DocumentGate>
{#snippet fallback()}
<p class="loading">Loading…</p>
{/snippet}
<FontPreview />
</DocumentGate>
</Viewer>Your own editor#
To lay text out yourself, ask what the engine will do. resolve() says which font a write will
draw each run of text in; getRunCss(run) gives the CSS for a run as it answered.
getPaintFonts(font, text) gives the fonts themselves, measured as the browser draws them: what
@embedpdf/core-text lays text out with, so it breaks lines where the engine will. See
Show typed text in a browser for what
each answer holds.
Methods#
Everything useFonts() gives you.
| Method | What it does |
|---|---|
ensureLoaded() | Reads the document’s fonts unless they’re loaded or loading. Resolves once they’re there. |
refresh() | Reads them again. Rarely needed: the list keeps up by itself. |
resolve(request) | The fonts a write would draw each run in, without writing. Your own editor |
getProgram(displayHash) | A font file’s facts: the characters it covers and its line metrics. |
getFontCss(font) | The CSS text in a font is drawn with, and the programs it names. Draw text in a font |
getFaceCss(face) | The same for a face, as rich text names one: { family, weight, italic }. |
getRunCss(run) | The same for a run as resolve() answered it. |
getPaintFonts(font, text) | The fonts a box in font draws text in, measured; null while they load. Your own editor |
getPaintFontsEpoch() | A number that moves when any of the answers above may change: ask again when it does. |
getFaceOfCssFamily(cssFamily) | The face a program’s CSS family stands for, to read back text the browser drew itself. |
resolve() and getProgram() also take a signal in their options, to cancel them.
State#
Everything useFontsState() gives you, as one reactive object: read its fields, and your markup updates when they change. The method in the last column reads the same value once.
| Field | What it is | Read once |
|---|---|---|
fonts | Every font the document can be written in, as listed under The fonts you can use, or null until the list has loaded | getFontList() |
status | 'idle' until something asks for the list, then 'loading', 'ready', 'forbidden' or 'error' | getStatus() |
Events#
| Event | Fires when | Carries |
|---|---|---|
onFontListChanged | The list was loaded, or changed: a write put a font in the document, or the engine’s fonts changed | fonts |
Good to know#
Fonts that stay on the engine#
A font whose file can’t go to a browser, one the PDF only names or a server font kept on the server, is drawn in the standard font the engine falls back to for it while text is typed. The engine’s own picture of the box follows the write.
On the cloud#
Downloading a font file needs a token that may write text in the document. With a read-only token the list is still there; the standard fonts, which come with the viewer, show as they are, and any other font in the system’s closest font.
Your feedback goes directly to the documentation team.