Authoring guide
This page covers the patterns we use when building real documents — the “why” behind the API, plus a few concrete templates you can lift.
Build the document as a React tree
Treat the document like any other component. Take props, derive content, return JSX. The shape is the same whether you’re generating from data or hand-authoring.
function Invoice({ client, lineItems }: Props) { const total = lineItems.reduce((s, l) => s + l.qty * l.unit, 0); return ( <Document pageSize="letter" meta={{ title: `Invoice ${invoiceId}`, author: 'helixui' }} exportFileName={`invoice-${invoiceId}.docx`} > <Heading level={1} align="right">Invoice #{invoiceId}</Heading> <Paragraph>Bill to: {client.name}</Paragraph>
<DocTable header={['Item', 'Qty', 'Unit', 'Total']} rows={lineItems.map((l) => [l.name, l.qty, fmt(l.unit), fmt(l.qty * l.unit)])} colWidths={[3.6, 0.7, 1.2, 1.4]} />
<Paragraph align="right"> <DocText size={14} weight="bold" color="brand">Total · {fmt(total)}</DocText> </Paragraph> </Document> );}Compose at the block level, style at the run level
Blocks (<Heading>, <Paragraph>, <DocList>, <DocTable>) own layout —
alignment, indentation, spacing. Inline runs (<DocText>, <DocLink>)
own visual style — bold, color, font.
This split keeps the API tight and matches how Word itself thinks about documents.
<Paragraph align="justify" indent={0.25}> The platform team will own{' '} <DocText weight="semibold" color="brand">tokens</DocText> and{' '} <DocText weight="semibold" color="brand">docs</DocText> through Q3.</Paragraph>Common patterns
Section header + body
<Heading level={2}>Risks</Heading><DocList type="number"> <DocListItem>Browser-side DOCX export is heavier than PPTX.</DocListItem> <DocListItem>Image embedding requires CORS-friendly sources.</DocListItem></DocList>Two-column figures (with sections)
@helixui/document doesn’t ship a column primitive. For a wide figure or
chart, switch the section to landscape:
<DocSection orientation="landscape" margins={{ top: 0.5, right: 0.5, bottom: 0.5, left: 0.5 }}> <Heading level={2}>Architecture</Heading> <DocImage src="/architecture.svg" w={10} h={6} align="center" /></DocSection>Right-aligned totals
For invoices and receipts, set align="right" on the totals paragraphs.
Color the grand total with <DocText color="brand"> so it pops without
needing a separate style.
<Paragraph align="right"> Subtotal: <DocText weight="semibold">$ 22,820</DocText></Paragraph><Paragraph align="right"> <DocText size={14} weight="bold" color="brand">Total · $ 25,102</DocText></Paragraph>Highlighted runs
highlight maps to docx’s named highlight enum. Pass a theme key and the
exporter will pick the closest match.
<DocText highlight="success">Added</DocText><DocText highlight="brand">Changed</DocText><DocText highlight="danger">Removed</DocText>Code blocks with language hints
The language prop is preserved as a data-language attribute in the DOM
preview and is currently informational on export — Word doesn’t render
syntax highlighting natively. Use it anyway, future versions can pre-render
highlighted spans.
<DocCodeBlock language="ts">{`await exportToDocx(<Brief />);`}</DocCodeBlock>Page breaks vs sections
Use <DocPageBreak> when you only want a new page — same page setup.
Use <DocSection> when you want a new page and a setup change
(orientation, margins, page size).
Generating from data
Any list of records → a document. Map to React, hand to exportToDocx.
async function downloadChangelog(releases: Release[]) { const doc = ( <Document meta={{ title: 'Changelog', author: 'helixui' }} exportFileName="changelog.docx"> <Heading level={1}>Changelog</Heading> {releases.map((r) => ( <React.Fragment key={r.version}> <Heading level={2}>{r.version} — {r.date}</Heading> <DocList> {r.notes.map((n, i) => <DocListItem key={i}>{n}</DocListItem>)} </DocList> </React.Fragment> ))} </Document> ); await exportToDocx(doc);}Don’t over-style
Word handles defaults well. Body text doesn’t need an explicit size or
color — the theme’s bodyFontSize and colors.ink already apply.
Lean on the theme; reserve inline overrides for emphasis.
Preview before exporting
The same React tree feeds both the DOM preview and the exporter. Render the document in your app, let the user review it, then attach the export to a button:
const docEl = <Brief />;
return ( <> {docEl} <Button onClick={() => exportToDocx(docEl)}>Download .docx</Button> </>);You can also attach the document to email or upload it without triggering
a download by calling documentToDocxBlob() instead.