Open Source

Flutter package

docs_gee

Pure Dart DOCX and PDF generation from a single document model — no native dependencies, runs everywhere Dart runs.

v1.4.222.8k / month31 likesMITAll platforms incl. WASMDOCX + PDF

Document building guide

Rich text, semantic styles, tables, nested lists, hyperlinks, bookmarks, table of contents and page breaks.

source: README.md

Guide

Rich text runs

A paragraph is a list of TextRuns. Each run carries its own formatting, so you can mix weights, styles, colors and highlights inside a single line. Colors are hex strings without the # prefix.

dart
doc.addParagraph(Paragraph(
  runs: [
    TextRun('Normal, '),
    TextRun('bold, ', bold: true),
    TextRun('italic, ', italic: true),
    TextRun('red text, ', color: 'FF0000'),
    TextRun('highlighted', backgroundColor: 'FFFF00'),
  ],
));
PropertyTypeDescription
boldboolBold text
italicboolItalic text
underlineboolUnderlined text
strikethroughboolStrikethrough text
colorStringHex color (e.g. FF0000), without the # prefix
backgroundColorStringHighlight color
hyperlinkString?External URL link
bookmarkRefString?Internal bookmark reference
isLineBreakboolLine break (use TextRun.lineBreak())

Semantic styles

Named factories give each paragraph a real Word style — headings, subtitle, quote, code block, caption and footnote — so the output maps to the document outline instead of hand-tuned font sizes.

dart
doc.addParagraph(Paragraph.heading('Title', level: 1));
doc.addParagraph(Paragraph.subtitle('Document subtitle'));
doc.addParagraph(Paragraph.quote('A famous quote...'));
doc.addParagraph(Paragraph.codeBlock('const x = 42;'));
doc.addParagraph(Paragraph.caption('Figure 1: Chart'));
doc.addParagraph(Paragraph.footnote('1. Reference note'));
StyleMethod
Normal textParagraph.text('...')
Heading 1-4Paragraph.heading('...', level: 1)
SubtitleParagraph.subtitle('...')
CaptionParagraph.caption('...')
QuoteParagraph.quote('...')
Code blockParagraph.codeBlock('...')
FootnoteParagraph.footnote('...')

Headings run from level 1 to level 4:

dart
doc.addParagraph(Paragraph.heading('Heading Level 1', level: 1));
doc.addParagraph(Paragraph.heading('Heading Level 2', level: 2));
doc.addParagraph(Paragraph.heading('Heading Level 3', level: 3));
doc.addParagraph(Paragraph.heading('Heading Level 4', level: 4));

Spacing

Since 1.3.4, Paragraph.empty() inserts a blank spacer paragraph — useful as vertical spacing between content blocks.

Alignment

Every paragraph factory accepts an alignment argument. Alignment has four values — left, center, right and justify (justify maps to the OOXML both value).

dart
doc.addParagraph(Paragraph.text('Centered', alignment: Alignment.center));
doc.addParagraph(Paragraph.text('Right aligned', alignment: Alignment.right));
doc.addParagraph(Paragraph.text('Justified body', alignment: Alignment.justify));

Tables

A Table is rows of cells. Set borders and background colors at the table level, and override alignment or backgrounds per cell.

dart
doc.addTable(Table(
  borders: TableBorders.all(),
  rows: [
    TableRow(cells: [
      TableCell.text('Name', backgroundColor: 'CCCCCC'),
      TableCell.text('Score', backgroundColor: 'CCCCCC'),
    ]),
    TableRow(cells: [
      TableCell.text('Alice'),
      TableCell.text('95', alignment: Alignment.right),
    ]),
  ],
));

Individual cells can override the table borders entirely — custom colors, a single side, or none at all. Border width is measured in eighths of a point (4 = 0.5pt, 8 = 1pt).

dart
doc.addTable(Table(
  borders: const TableBorders.all(),
  rows: [
    TableRow(cells: [
      // Cell with custom red borders
      TableCell.text('Alert', borders: const CellBorders.all(color: 'FF0000', size: 8)),
      TableCell.text('Normal cell'),
    ]),
    TableRow(cells: [
      // Cell with only bottom border
      TableCell.text('Underlined', borders: const CellBorders.bottom()),
      // Cell with no borders (overrides table borders)
      TableCell.text('Clean', borders: const CellBorders.none()),
    ]),
  ],
));

// Selective sides with different styles
TableCell(
  paragraphs: [Paragraph.text('Custom')],
  borders: const CellBorders(
    top: Border(color: 'FF0000', size: 8, style: BorderStyle.double),
    bottom: Border(color: '0000FF'),
  ),
);

Lists & nesting

There are five list markers, each its own factory. Add items in sequence to build a list.

MethodMarker
Paragraph.bulletItem('...')• bullet
Paragraph.dashItem('...')- dash
Paragraph.numberedItem('...')1, 2, 3…
Paragraph.alphaItem('...')a, b, c…
Paragraph.romanItem('...')I, II, III…
dart
// Bullet list
doc.addParagraph(Paragraph.bulletItem('First item'));
doc.addParagraph(Paragraph.bulletItem('Second item'));

// Numbered list
doc.addParagraph(Paragraph.numberedItem('Step one'));
doc.addParagraph(Paragraph.numberedItem('Step two'));

// Nested list
doc.addParagraph(Paragraph.bulletItem('Parent'));
doc.addParagraph(Paragraph.bulletItem('Child', indentLevel: 1));

Nesting is driven by indentLevel, and list types can be mixed at different depths:

dart
doc.addParagraph(Paragraph.numberedItem('First item'));
doc.addParagraph(Paragraph.alphaItem('Sub-item a', indentLevel: 1));
doc.addParagraph(Paragraph.alphaItem('Sub-item b', indentLevel: 1));
doc.addParagraph(Paragraph.romanItem('Detail i', indentLevel: 2));
doc.addParagraph(Paragraph.numberedItem('Second item'));

Nesting depth

indentLevel starts at 0 (top level); the maximum supported level is 8, which the README markets as "up to 9 levels" (levels 0 through 8).

Table of contents

Turn on includeTableOfContents and docs_gee builds a linked TOC from your headings automatically. tocMaxLevel controls how deep it goes (default 3, i.e. Heading 1-3). The automatic table of contents is DOCX-only.

dart
// Enable automatic Table of Contents
final doc = Document(
  title: 'My Document',
  includeTableOfContents: true,
  tocTitle: 'Contents',
  tocMaxLevel: 3,  // Include Heading 1-3
);

doc.addParagraph(Paragraph.heading('Introduction', level: 1));
doc.addParagraph(Paragraph.heading('Getting Started', level: 2));
// TOC will be auto-generated with links to these headings

Breaks & emoji

Force a new page before a paragraph with pageBreakBefore:

dart
doc.addParagraph(Paragraph.heading(
  'New Chapter',
  level: 1,
  pageBreakBefore: true,
));

Soft line breaks — like Shift+Enter in Word — keep multiple lines inside one paragraph. Use \n in text, or explicit TextRun.lineBreak() runs for per-line formatting. Line breaks are DOCX-only.

dart
// Using \n in text (automatic conversion)
doc.addParagraph(Paragraph.text('Line 1\nLine 2\nLine 3'));

// Using explicit line break runs (for different formatting per line)
doc.addParagraph(Paragraph(
  runs: [
    TextRun('Bold line', bold: true),
    TextRun.lineBreak(),
    TextRun('Normal line'),
    TextRun.lineBreak(),
    TextRun('Italic line', italic: true),
  ],
));

Emoji render in DOCX, where Word handles them natively:

dart
doc.addParagraph(Paragraph.text('Hello World! 👋🌍'));

Heads up

Emoji are DOCX-only — PDF uses standard fonts without emoji support.

Let's make something together.

If you have any questions about a new project or other inquiries, feel free to contact us. We will get back to you as soon as possible.

Codigee
We are using cookies. Learn more