An advanced text layout framework for complex typography in PDF generation
npx @tessl/cli install tessl/npm-react-pdf--textkit@6.0.0@react-pdf/textkit is an advanced text layout framework specifically designed for complex typography in PDF generation. It implements a comprehensive 13-step text layout process including paragraph splitting, bidirectional text handling, font substitution and shaping, script itemization, line breaking, text justification, and text decoration.
npm install @react-pdf/textkitimport layoutEngine, {
bidi,
linebreaker,
justification,
textDecoration,
scriptItemizer,
wordHyphenation,
fontSubstitution,
fromFragments,
type AttributedString,
type Container,
type LayoutOptions,
type Engines
} from "@react-pdf/textkit";For CommonJS:
const layoutEngine = require("@react-pdf/textkit").default;
const {
bidi,
linebreaker,
justification,
textDecoration,
scriptItemizer,
wordHyphenation,
fontSubstitution,
fromFragments
} = require("@react-pdf/textkit");import layoutEngine, {
bidi,
linebreaker,
justification,
textDecoration,
scriptItemizer,
wordHyphenation,
fontSubstitution,
fromFragments
} from "@react-pdf/textkit";
// Create text fragments
const fragments = [
{ string: "Hello ", attributes: { fontSize: 16 } },
{ string: "World", attributes: { fontSize: 16, color: "blue" } }
];
// Create attributed string from fragments
const attributedString = fromFragments(fragments);
// Set up engines
const engines = {
bidi: bidi(),
linebreaker: linebreaker({ tolerance: 4 }),
justification: justification({}),
textDecoration: textDecoration(),
scriptItemizer: scriptItemizer(),
wordHyphenation: wordHyphenation(),
fontSubstitution: fontSubstitution()
};
// Create layout engine and perform layout
const layout = layoutEngine(engines);
const container = { x: 0, y: 0, width: 200, height: 100 };
const result = layout(attributedString, container);@react-pdf/textkit is built around several key components:
Core text layout functionality that orchestrates the complete 13-step text processing pipeline. Handles complex typography including bidirectional text, font shaping, line breaking, and justification.
function layoutEngine(engines: Engines): (
attributedString: AttributedString,
container: Container,
options?: LayoutOptions
) => AttributedString;
interface Engines {
bidi: typeof bidi;
linebreaker: typeof linebreaker;
justification: typeof justification;
textDecoration: typeof textDecoration;
scriptItemizer: typeof scriptItemizer;
wordHyphenation?: typeof wordHyphenation;
fontSubstitution: typeof fontSubstitution;
}Specialized engines for different aspects of text processing including bidirectional text reordering, line breaking with Knuth & Plass algorithm, text justification, and font substitution.
function bidi(): (attributedString: AttributedString) => AttributedString;
function linebreaker(options: LayoutOptions): (
attributedString: AttributedString,
availableWidths: number[]
) => AttributedString[];
function justification(options: LayoutOptions): (line: AttributedString) => AttributedString;
function fontSubstitution(): (attributedString: AttributedString) => AttributedString;Core utilities for creating styled text. Provides functions for constructing attributed strings from text fragments.
function fromFragments(fragments: Fragment[]): AttributedString;Utilities for text decoration (underlines, strike-through) and Unicode script itemization for proper text rendering across different writing systems.
function textDecoration(): (line: AttributedString) => AttributedString;
function scriptItemizer(): (attributedString: AttributedString) => AttributedString;
function wordHyphenation(): (word: string | null) => string[];Text Decoration & Script Processing
interface AttributedString {
string: string;
syllables?: string[];
runs: Run[];
box?: Rect;
decorationLines?: DecorationLine[];
overflowLeft?: number;
overflowRight?: number;
xAdvance?: number;
ascent?: number;
}
interface Fragment {
string: string;
attributes?: Attributes;
}
interface Container extends Rect {
truncateMode?: 'ellipsis';
maxLines?: number;
excludeRects?: Rect[];
}
interface LayoutOptions {
hyphenationCallback?: (word: string) => string[];
tolerance?: number;
hyphenationPenalty?: number;
expandCharFactor?: JustificationFactor;
shrinkCharFactor?: JustificationFactor;
expandWhitespaceFactor?: JustificationFactor;
shrinkWhitespaceFactor?: JustificationFactor;
}
interface JustificationFactor {
before: number;
after: number;
priority?: number;
unconstrained?: boolean;
}
interface Run {
start: number;
end: number;
attributes: Attributes;
glyphIndices?: number[];
glyphs?: Glyph[];
positions?: Position[];
xAdvance?: number;
height?: number;
descent?: number;
}
interface Attributes {
align?: string;
alignLastLine?: string;
attachment?: Attachment;
backgroundColor?: string;
bidiLevel?: number;
bullet?: unknown;
characterSpacing?: number;
color?: string;
direction?: 'rtl' | 'ltr';
features?: unknown[];
fill?: boolean;
font?: Font[];
fontSize?: number;
hangingPunctuation?: boolean;
hyphenationFactor?: number;
indent?: number;
justificationFactor?: number;
lineHeight?: number;
lineSpacing?: number;
link?: string;
margin?: number;
marginLeft?: number;
marginRight?: number;
opacity?: number;
padding?: number;
paddingTop?: number;
paragraphSpacing?: number;
scale?: number;
script?: unknown;
shrinkFactor?: number;
strike?: boolean;
strikeColor?: string;
strikeStyle?: string;
stroke?: boolean;
underline?: boolean;
underlineColor?: string;
underlineStyle?: string;
verticalAlign?: string;
wordSpacing?: number;
yOffset?: number;
}
interface Rect {
x: number;
y: number;
width: number;
height: number;
}
interface Position {
xAdvance: number;
yAdvance: number;
xOffset: number;
yOffset: number;
advanceWidth?: number;
}
interface DecorationLine {
rect: Rect;
opacity: number;
color: string;
style: string;
}
interface Attachment {
x?: number;
y?: number;
width: number;
height: number;
xOffset?: number;
yOffset?: number;
image: Buffer;
}
type Coordinate = {
x: number;
y: number;
};
type Glyph = FontkitGlyph;
type Paragraph = AttributedString[];