How Does Layout Work in react-pdf?
Updated
react-pdf uses Yoga to bring flexbox layout to PDF pages, so you position elements with the same mental model you already use for CSS: rows, columns, wrapping, and absolute positioning. If you are comfortable with flexbox in the browser, the main adjustment is that you are laying out fixed-size pages rather than a scrolling viewport, and you build the structure with React components instead of HTML tags.
The layout engine: Yoga, not the browser
react-pdf does not run your document through a browser rendering engine. It uses Yoga, a cross-platform layout engine that implements flexbox, to compute positions and sizes. That has two practical consequences:
- Flexbox is the primary layout tool. You get
flexDirection,justifyContent,alignItems,flexWrap,flex, and related properties onViewcomponents. - There is no CSS cascade or stylesheet. Styles are JavaScript objects passed to a
styleprop, and they are resolved per component rather than inherited through a global cascade.
Because the same document definition renders to a file, a stream, or a blob — in Node or in the client — the layout result is consistent across server and browser, which matters when you generate the same invoice or report in both places.
Building a page structure with React components
The layout primitives are React components, not HTML elements:
| Component | Role in layout |
|---|---|
Document |
Root container; holds page-level metadata |
Page |
A fixed-size canvas; you set size and style here |
View |
The flex container/box — your main layout building block |
Text |
Text content, which must live inside a Text or View context |
A minimal structure looks like this:
import { Document, Page, View, Text, StyleSheet } from '@react-pdf/renderer';
const styles = StyleSheet.create({
page: { flexDirection: 'column', padding: 30 },
row: { flexDirection: 'row', justifyContent: 'space-between' },
column: { flexGrow: 1, flexBasis: 0 },
});
const Invoice = () => (
<Document>
<Page size="A4" style={styles.page}>
<View style={styles.row}>
<View style={styles.column}><Text>From</Text></View>
<View style={styles.column}><Text>To</Text></View>
</View>
</Page>
</Document>
);
The input is the component tree plus the style objects; the action is rendering; the expected result is a laid-out page where the two columns split the available width evenly. Note that flexDirection defaults to column in react-pdf, unlike the browser default of row — a common source of surprise when porting CSS.
What carries over from CSS flexbox
- Rows and columns:
flexDirection: 'row' | 'column'controls the main axis. - Distribution:
justifyContentandalignItemsbehave as you expect along the main and cross axes. - Wrapping:
flexWrap: 'wrap'lets children flow onto multiple lines. - Absolute positioning:
position: 'absolute'withtop,left,right,bottomtakes an element out of flow — useful for headers, footers, and watermarks. - Sizing:
width,height,flexGrow,flexShrink, andflexBasiswork onViewboxes.
Where it differs from the browser
- No scrolling viewport. A
Pageis a fixed canvas. Content that overflows does not scroll; you control it with page breaks. - Page-break control is explicit. The docs list page-break control as a feature, so you manage where content splits rather than relying on the browser.
- Units and defaults differ. Sizes are in points, and as noted, the default flex direction is column.
- Text is special. Text must be wrapped in
Textcomponents; you cannot drop raw strings into aViewand expect them to lay out like inline HTML.
Beyond boxes: fonts, images, and SVG
Layout is not only about boxes. The renderer supports custom fonts, images, SVG, form fields, and hyphenation, all of which participate in the same flexbox flow. An image inside a View with flexGrow will size according to the flex rules, and hyphenation affects how text wraps inside its container — so text-heavy layouts benefit from testing with your actual font and content length.
A practical way to verify layout
- Install the renderer:
npm install @react-pdf/renderer. - Build a small document with one
Pageand a couple of nestedViewrows. - Render it to a file or blob and open the result.
- Adjust
flexDirection,justifyContent, andflexBasisuntil the boxes land where you want.
The playground linked from the site is the fastest loop for this, since you can change styles and see the page without wiring up a full build.
If your goal is a document whose structure mirrors a familiar CSS flexbox layout — rows, columns, wrapping, absolute overlays — react-pdf is a direct fit. If you need a scrolling, reflowing web page rather than fixed pages, or you depend on the full CSS cascade, flexbox alone will not cover that, and you should treat the layout model as a constrained subset rather than a browser equivalent.