Skip to main content
Forme provides 19 components for building PDF documents. All components are imported from @formepdf/react.
import {
  Document, Page, View, Text, Image, Svg, QrCode, Barcode,
  Table, Row, Cell, Fixed, PageBreak, Canvas, Watermark,
  BarChart, LineChart, PieChart, AreaChart, DotPlot,
} from '@formepdf/react';

Styling

Styles are plain objects passed to the style prop. You can write them inline or extract them with StyleSheet.create() for TypeScript autocomplete:
import { StyleSheet } from '@formepdf/react';

const styles = StyleSheet.create({
  heading: { fontSize: 24, fontWeight: 700 },
  body: { fontSize: 10, lineHeight: 1.6 },
});

<Text style={styles.heading}>Title</Text>
StyleSheet.create() is an identity function. It returns the same object you pass in. Its purpose is to provide autocomplete and type checking on style properties.

Document

Root container for every Forme document. All other components must be descendants of <Document>.

Props

PropTypeDefaultDescription
titlestring-PDF metadata title
authorstring-PDF metadata author
subjectstring-PDF metadata subject
creatorstring-PDF metadata creator application
styleStyle-Default style for the entire document. Sets global fontFamily, fontSize, color, etc. Inherited by all children.
fontsFontRegistration[]-Custom fonts to register for this document. See Fonts.

Example

<Document title="Quarterly Report" author="Acme Corp" style={{ fontFamily: 'Inter', fontSize: 12 }}>
  <Page size="A4" margin={54}>
    <Text>Hello World</Text>
  </Page>
</Document>
Every Forme document starts with <Document>. If no <Page> children are provided, content uses the default page configuration (Letter size, 54pt margins).

Page

Defines a page boundary with explicit size and margin configuration. Content inside each <Page> is laid out independently.

Props

PropTypeDefaultDescription
size"A4" | "Letter" | "Legal" | "A3" | "A5" | "Tabloid" | { width, height }"Letter"Page dimensions. Custom sizes are in points (72 points = 1 inch).
marginnumber | { top, right, bottom, left }54Page margins in points. A single number applies to all sides.

Example

{/* Standard Letter page with 1-inch margins */}
<Page size="Letter" margin={72}>
  <Text>US Letter</Text>
</Page>

{/* Custom 4x6 shipping label */}
<Page size={{ width: 288, height: 432 }} margin={16}>
  <Text>Shipping Label</Text>
</Page>

{/* A4 with different margins per side */}
<Page size="A4" margin={{ top: 72, right: 54, bottom: 72, left: 54 }}>
  <Text>A4 with asymmetric margins</Text>
</Page>
Content that exceeds the page height automatically flows to additional pages with the same size and margins.

View

A flex container, analogous to an HTML <div>. Defaults to column layout.

Props

PropTypeDefaultDescription
styleStyle-CSS-like style properties
wrapbooleantrueWhether this container can break across pages. Set to false to keep all children on the same page.
hrefstring-URL to link to. Makes the entire View a clickable link in the PDF.
bookmarkstring-Adds a PDF outline (bookmark) entry with this label. Readers can jump to this View from the bookmark panel.

Example

{/* Row layout with gap */}
<View style={{ flexDirection: 'row', gap: 12 }}>
  <Text>Left</Text>
  <Text>Right</Text>
</View>

{/* Card that stays on one page */}
<View wrap={false} style={{ padding: 16, backgroundColor: '#f8fafc', borderRadius: 8 }}>
  <Text style={{ fontWeight: 700 }}>Important Card</Text>
  <Text>This content will not split across pages.</Text>
</View>

{/* Absolute positioning */}
<View style={{ width: 200, height: 80, backgroundColor: '#f1f5f9' }}>
  <Text>Card content</Text>
  <View style={{ position: 'absolute', top: 4, right: 4, padding: 4, backgroundColor: '#ef4444', borderRadius: 4 }}>
    <Text style={{ fontSize: 8, color: '#fff', fontWeight: 700 }}>SALE</Text>
  </View>
</View>
Views use flexbox column layout by default. All flex properties (flexDirection, justifyContent, alignItems, flexWrap, gap, flexGrow, flexShrink) are supported. Set position: 'absolute' in the style to position a View relative to its parent’s content box.

Text

Renders text content with font properties, colors, and alignment.

Props

PropTypeDefaultDescription
styleStyle-Typography and color styles
childrenstring | number | Text-Text content. Nest <Text> inside <Text> for inline styling (bold a word, change colors mid-sentence).
hrefstring-URL to link to. Makes this text a clickable link in the PDF.
bookmarkstring-Adds a PDF outline (bookmark) entry with this label.

Example

{/* Heading */}
<Text style={{ fontSize: 24, fontWeight: 700, color: '#1e293b' }}>
  Invoice #2024-001
</Text>

{/* Body text with line height */}
<Text style={{ fontSize: 10, lineHeight: 1.6, color: '#475569' }}>
  Payment is due within 30 days of the invoice date. Late payments
  are subject to a 1.5% monthly finance charge.
</Text>

{/* Clickable link */}
<Text href="https://example.com" style={{ color: '#2563eb', textDecoration: 'underline' }}>
  Visit our website
</Text>

{/* Bookmark (appears in PDF outline panel) */}
<Text bookmark="Chapter 1" style={{ fontSize: 20, fontWeight: 700 }}>
  Chapter 1: Introduction
</Text>

{/* Inline styling with nested Text */}
<Text style={{ fontSize: 10 }}>
  This sentence has a <Text style={{ fontWeight: 700 }}>bold word</Text> and a{' '}
  <Text style={{ color: '#ef4444' }}>red word</Text> in the middle.
</Text>

{/* Strikethrough pricing */}
<Text style={{ fontSize: 14 }}>
  $42.00 <Text style={{ textDecoration: 'line-through', color: '#94a3b8' }}>$56.00</Text>
</Text>

{/* Dynamic page numbers */}
<Text style={{ fontSize: 9, textAlign: 'center' }}>
  Page {'{{pageNumber}}'} of {'{{totalPages}}'}
</Text>
Text wraps automatically based on the available width. Use {{pageNumber}} and {{totalPages}} placeholders for dynamic page numbering. Nested <Text> elements share the same line and can have different styles, which is useful for inline formatting like bold words, colored spans, or strikethrough pricing.

Image

Embeds a JPEG or PNG image. Aspect ratio is preserved when only one dimension is specified.

Props

PropTypeDefaultDescription
srcstring(required)Image source: base64 data URI (data:image/png;base64,...) or file path
widthnumber-Display width in points
heightnumber-Display height in points
styleStyle-Additional style properties (margin, etc.)

Example

{/* From file path */}
<Image src="./logo.png" width={120} />

{/* From data URI with both dimensions */}
<Image src="data:image/png;base64,iVBOR..." width={200} height={100} />

{/* With margin */}
<Image src="./photo.jpg" width={300} style={{ marginBottom: 16 }} />
If only width is provided, height is calculated from the image’s aspect ratio (and vice versa). Both JPEG and PNG formats are supported, including PNG transparency.

Table

Table container with column definitions. Children should be <Row> elements.

Props

PropTypeDefaultDescription
columnsColumnDef[]-Column width definitions
styleStyle-Style properties for the table container

Column width types

TypeExampleDescription
{ fraction: number }{ fraction: 0.5 }Proportional width (0.5 = 50% of table width)
{ fixed: number }{ fixed: 100 }Fixed width in points
"auto""auto"Size to content

Example

<Table columns={[
  { width: { fraction: 0.5 } },
  { width: { fraction: 0.2 } },
  { width: { fraction: 0.15 } },
  { width: { fraction: 0.15 } }
]}>
  <Row header style={{ backgroundColor: '#1e293b' }}>
    <Cell style={{ padding: 8 }}><Text style={{ color: '#fff', fontWeight: 700 }}>Item</Text></Cell>
    <Cell style={{ padding: 8 }}><Text style={{ color: '#fff', fontWeight: 700 }}>Qty</Text></Cell>
    <Cell style={{ padding: 8 }}><Text style={{ color: '#fff', fontWeight: 700 }}>Price</Text></Cell>
    <Cell style={{ padding: 8 }}><Text style={{ color: '#fff', fontWeight: 700 }}>Total</Text></Cell>
  </Row>
  <Row>
    <Cell style={{ padding: 8 }}><Text>Widget</Text></Cell>
    <Cell style={{ padding: 8 }}><Text>5</Text></Cell>
    <Cell style={{ padding: 8 }}><Text>$10.00</Text></Cell>
    <Cell style={{ padding: 8 }}><Text>$50.00</Text></Cell>
  </Row>
</Table>
Tables automatically break across pages between rows. Header rows (marked with header) are repeated at the top of each continuation page.

Row

A table row. Must be a direct child of <Table>.

Props

PropTypeDefaultDescription
headerbooleanfalseWhether this is a header row. Header rows repeat on every page when a table spans multiple pages.
styleStyle-Style properties (e.g., backgroundColor for alternating rows)

Example

{/* Header row that repeats on page breaks */}
<Row header style={{ backgroundColor: '#f1f5f9' }}>
  <Cell><Text style={{ fontWeight: 700 }}>Name</Text></Cell>
  <Cell><Text style={{ fontWeight: 700 }}>Value</Text></Cell>
</Row>

{/* Alternating row colors */}
<Row style={{ backgroundColor: '#ffffff' }}>
  <Cell><Text>Row 1</Text></Cell>
  <Cell><Text>Value 1</Text></Cell>
</Row>
<Row style={{ backgroundColor: '#f8fafc' }}>
  <Cell><Text>Row 2</Text></Cell>
  <Cell><Text>Value 2</Text></Cell>
</Row>

Cell

A table cell inside a <Row>.

Props

PropTypeDefaultDescription
colSpannumber1Number of columns this cell spans
rowSpannumber1Number of rows this cell spans
styleStyle-Style properties (padding, background, etc.)

Example

{/* Standard cell */}
<Cell style={{ padding: 8 }}>
  <Text>Cell content</Text>
</Cell>

{/* Spanning two columns */}
<Cell colSpan={2} style={{ padding: 8, backgroundColor: '#f1f5f9' }}>
  <Text>This spans two columns</Text>
</Cell>
Cells can contain any Forme element, not just Text.

Svg

Renders inline SVG graphics. Supports basic SVG elements: rect, circle, ellipse, line, polyline, polygon, and path. Elements support opacity, fill-opacity, and stroke-opacity attributes with proper inheritance through <g> groups.

Props

PropTypeDefaultDescription
widthnumber(required)Display width in points
heightnumber(required)Display height in points
viewBoxstring-SVG viewBox attribute (e.g., "0 0 100 100")
contentstring-SVG markup string containing the elements to render
childrenReactNode-JSX children as an alternative to content
styleStyle-Additional style properties (margin, etc.)
Provide either content (a raw SVG string) or JSX children — not both. If both are provided, content takes priority.

Example — content string

{/* Simple shapes */}
<Svg width={100} height={100} viewBox="0 0 100 100"
  content='<rect x="10" y="10" width="80" height="80" fill="#3b82f6" rx="8" />' />

{/* Circle with stroke */}
<Svg width={60} height={60} viewBox="0 0 60 60"
  content='<circle cx="30" cy="30" r="25" fill="none" stroke="#1e293b" stroke-width="2" />' />

{/* Path element */}
<Svg width={200} height={100} viewBox="0 0 200 100"
  content='<path d="M10 80 Q 95 10 180 80" fill="none" stroke="#ef4444" stroke-width="3" />' />

Example — JSX children

{/* Same shapes using JSX syntax */}
<Svg width={100} height={100} viewBox="0 0 100 100">
  <rect x="10" y="10" width="80" height="80" fill="#3b82f6" rx="8" />
</Svg>

{/* Grouped elements with inherited opacity */}
<Svg width={200} height={100} viewBox="0 0 200 100">
  <g opacity="0.5">
    <rect x="10" y="10" width="80" height="80" fill="#3b82f6" />
    <circle cx="150" cy="50" r="40" fill="#ef4444" />
  </g>
</Svg>
JSX children are serialized to SVG XML automatically. CamelCase props like strokeWidth are converted to their kebab-case SVG equivalents (stroke-width). SVG content is rendered directly into the PDF using native PDF drawing operations, not rasterized. This produces crisp vector output at any zoom level.

QrCode

Renders a QR code from a data string. Output is vector-based (not a raster image), so it stays crisp at any zoom level.

Props

PropTypeDefaultDescription
datastring(required)The data to encode (URL, text, etc.)
sizenumber-Display size in points. QR codes are always square. Defaults to the available width.
colorstring"#000000"Color of the dark modules
styleStyle-Additional style properties (margin, etc.)

Example

{/* QR code linking to a URL */}
<QrCode data="https://formepdf.com" size={100} />

{/* QR code with custom color */}
<QrCode data="https://example.com/order/12345" size={80} color="#1e293b" />

{/* QR code with margin */}
<QrCode data="SKU-9876" size={60} style={{ marginTop: 12 }} />
QR codes are rendered as filled rectangles in the PDF — one rectangle per dark module. This is a native vector representation, not an embedded image, which keeps file sizes small and output sharp.

Barcode

Renders a 1D barcode from a data string. Output is vector-based (filled rectangles), crisp at any zoom level.

Props

PropTypeDefaultDescription
datastring(required)The data to encode
format"Code128" | "Code39" | "EAN13" | "EAN8" | "Codabar""Code128"Barcode format
widthnumber-Display width in points. Defaults to available width.
heightnumber60Bar height in points
colorstring"#000000"Color of the bars
styleStyle-Additional style properties (margin, etc.)

Example

{/* Code 128 barcode (default format) */}
<Barcode data="ABC-123" width={200} height={50} />

{/* EAN-13 barcode */}
<Barcode data="5901234123457" format="EAN13" width={180} height={60} />

{/* Code 39 with custom color */}
<Barcode data="HELLO" format="Code39" width={250} height={40} color="#1e293b" />
Barcodes are rendered as filled rectangles in the PDF — one rectangle per dark bar. Supported formats: Code 128 (general purpose), Code 39 (alphanumeric), EAN-13 (retail products), EAN-8 (small packages), and Codabar (libraries, blood banks).

Fixed

An element that repeats on every page as a header or footer. Reduces the available content area on each page.

Props

PropTypeDefaultDescription
position"header" | "footer"(required)Whether to place at the top or bottom of each page
styleStyle-Style properties

Example

<Page size="Letter" margin={54}>
  <Fixed position="header">
    <View style={{ flexDirection: 'row', justifyContent: 'space-between', paddingBottom: 8, borderWidth: { top: 0, right: 0, bottom: 1, left: 0 }, borderColor: '#e2e8f0' }}>
      <Text style={{ fontSize: 10, fontWeight: 700 }}>Acme Corp</Text>
      <Text style={{ fontSize: 10, color: '#64748b' }}>Confidential</Text>
    </View>
  </Fixed>

  <Fixed position="footer">
    <Text style={{ fontSize: 9, textAlign: 'center', color: '#94a3b8' }}>
      Page {'{{pageNumber}}'} of {'{{totalPages}}'}
    </Text>
  </Fixed>

  {/* Page content goes here */}
  <Text>This content area is reduced by the header and footer heights.</Text>
</Page>
Use {{pageNumber}} and {{totalPages}} placeholders inside Fixed elements for automatic page numbering.

PageBreak

Forces content after this element to start on a new page.

Props

None.

Example

<Text>This is on page 1.</Text>
<PageBreak />
<Text>This is on page 2.</Text>
PageBreak is useful for separating document sections (e.g., cover page from content, or chapters from each other).

Canvas

Renders arbitrary vector graphics via a draw callback. The callback receives a recording context with a Canvas-like API. All drawing commands are serialized and rendered as native PDF vector operations.

Props

PropTypeDescription
widthnumberCanvas width in points.
heightnumberCanvas height in points.
draw(ctx: CanvasContext) => voidDrawing callback.

CanvasContext methods

moveTo(x, y), lineTo(x, y), line(x1, y1, x2, y2), bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y), quadraticCurveTo(cpx, cpy, x, y), arc(cx, cy, r, startAngle, endAngle, counterclockwise?), circle(cx, cy, r), rect(x, y, w, h), ellipse(cx, cy, rx, ry), closePath(), stroke(), fill(), setFillColor(r, g, b), setStrokeColor(r, g, b), setLineWidth(w), setLineCap(cap), setLineJoin(join), save(), restore(). line(x1, y1, x2, y2) is a convenience that emits moveTo + lineTo + stroke in one call. Colors use 0-255 RGB values (like HTML Canvas). Content is clipped to the canvas bounds (matching HTML Canvas behavior).

Example

<Canvas
  width={200}
  height={100}
  draw={(ctx) => {
    ctx.setFillColor(59, 130, 246);
    ctx.rect(10, 10, 80, 80);
    ctx.fill();

    ctx.setStrokeColor(15, 23, 42);
    ctx.setLineWidth(2);
    ctx.arc(150, 50, 40, 0, Math.PI * 2);
    ctx.stroke();
  }}
/>

BarChart

Engine-native bar chart rendered directly to PDF vector graphics.

Props

PropTypeDefaultDescription
widthnumberChart width in points.
heightnumberChart height in points.
dataChartDataPoint[]Data points ({ label, value, color? }).
colorstring'#1a365d'Default bar color (hex). Per-item color overrides this.
showLabelsbooleantrueShow category labels on the X axis.
showGridbooleanfalseShow horizontal grid lines.
showValuesbooleanfalseShow value labels above bars.
titlestringChart title displayed above the chart.

Example

<BarChart
  width={400}
  height={200}
  data={[
    { label: 'Jan', value: 42 },
    { label: 'Feb', value: 58 },
    { label: 'Mar', value: 45 },
  ]}
  color="#3b82f6"
  showGrid
  showValues
/>

LineChart

Engine-native multi-series line chart with optional data points and grid.

Props

PropTypeDefaultDescription
widthnumberChart width in points.
heightnumberChart height in points.
seriesChartSeries[]Data series ({ name, data: number[], color? }).
labelsstring[]X-axis labels (one per data point).
showPointsbooleanfalseShow dots at data points.
showGridbooleanfalseShow horizontal grid lines.
titlestringChart title.

Example

<LineChart
  width={400}
  height={200}
  series={[
    { name: 'Revenue', data: [120, 190, 160, 220], color: '#3b82f6' },
    { name: 'Expenses', data: [80, 110, 95, 130], color: '#ef4444' },
  ]}
  labels={['Q1', 'Q2', 'Q3', 'Q4']}
  showGrid
  showPoints
/>

PieChart

Engine-native pie or donut chart with optional legend.

Props

PropTypeDefaultDescription
widthnumberChart width in points.
heightnumberChart height in points.
dataChartDataPoint[]Slices ({ label, value, color? }). Each slice should have a color.
donutbooleanfalseCut out the center to create a donut chart.
showLegendbooleanfalseShow a legend beside the chart.
titlestringChart title.

Example

<PieChart
  width={200}
  height={200}
  data={[
    { label: 'Product', value: 42, color: '#3b82f6' },
    { label: 'Services', value: 28, color: '#0f172a' },
    { label: 'Other', value: 30, color: '#cbd5e1' },
  ]}
  donut
  showLegend
/>

AreaChart

Engine-native multi-series area chart — like LineChart with semi-transparent fill under each line.

Props

PropTypeDefaultDescription
widthnumberChart width in points.
heightnumberChart height in points.
seriesChartSeries[]Data series ({ name, data: number[], color? }).
labelsstring[]X-axis labels.
showGridbooleanfalseShow horizontal grid lines.
titlestringChart title.

Example

<AreaChart
  width={400}
  height={200}
  series={[
    { name: 'Organic', data: [500, 800, 1200, 1800], color: '#3b82f6' },
    { name: 'Paid', data: [200, 400, 600, 900], color: '#f59e0b' },
  ]}
  labels={['Q1', 'Q2', 'Q3', 'Q4']}
  showGrid
  title="Traffic Sources"
/>

DotPlot

Engine-native scatter plot for (x, y) data with multiple groups.

Props

PropTypeDefaultDescription
widthnumberChart width in points.
heightnumberChart height in points.
groupsDotPlotGroup[]Groups ({ name, color?, data: [x, y][] }).
xMin / xMaxnumberautoX-axis range.
yMin / yMaxnumberautoY-axis range.
xLabelstringX-axis label.
yLabelstringY-axis label.
showLegendbooleanfalseShow legend.
dotSizenumber4Dot radius in points.

Example

<DotPlot
  width={300}
  height={200}
  groups={[
    { name: 'API v1', color: '#3b82f6', data: [[10, 45], [50, 120], [100, 230]] },
    { name: 'API v2', color: '#10b981', data: [[10, 25], [50, 60], [100, 110]] },
  ]}
  xLabel="Requests"
  yLabel="Latency (ms)"
  showLegend
/>

Watermark

Renders rotated text behind all page content. Automatically repeated on every page.

Props

PropTypeDefaultDescription
textstringWatermark text.
fontSizenumber60Font size in points.
colorstring'rgba(0,0,0,0.1)'Text color (supports rgba()).
anglenumber-45Rotation angle in degrees.

Example

<Page size="Letter" margin={54}>
  <Watermark text="DRAFT" fontSize={72} color="rgba(0,0,0,0.05)" angle={-45} />
  <Text>Document content here...</Text>
</Page>

Forms

Forme supports AcroForm components for creating fillable PDF forms. See the Forms page for full documentation.
ComponentDescription
<TextField>Text input field. Supports multiline, password, read-only.
<Checkbox>Checkbox with checked/unchecked state.
<Dropdown>Select dropdown with predefined options.
<RadioButton>Radio button, grouped by shared name.