HTML and CSS support

View Source

Use the renderer for reports, invoices, statements, forms, and labels. Start with a working example, then choose the features you need below. Unsupported HTML or CSS returns an error rather than being silently ignored.

HTML support

ContentSupported elements
Documenthtml, head, body, title, meta, style, and an HTML doctype
Headings and sectionsh1 through h6, p, div, section, article, aside, header, footer, main, nav
Inline textspan, strong, b, em, i, a, br, and character references such as &
Listsul, ol, li
Tablestable, caption, colgroup, col, thead, tbody, tfoot, tr, th, td
Imagesimg with a src
Form controlsText, checkbox, and radio input; select, option, textarea, button

Quote attribute values and close non-void tags. Put inline elements and form controls inside a block such as div or p. They cannot sit directly under body or at the document root. Supported controls create editable AcroForm fields by default. Use forms: :static for static artwork. See field naming and filling. Links support http://, https://, and mailto: destinations.

Use id, class, and style to apply CSS. Supported elements also accept relevant image, link, table-span, and form-value attributes.

CSS support

I needSupported CSS
Select elementsTag, class, ID, universal, attribute presence/equality, descendant and child selectors; comma groups; simple :not(); :root; first/last child and type selectors; :nth-child(odd/even/n)
Reuse stylesThe cascade, !important, inherited text styles, custom properties, var(), currentColor
Arrange contentBlock, inline, inline-block, flex, and grid layouts; relative and absolute positioning; z-index
Set sizes and spacingWidth/height, min/max sizes, min(), aspect ratio, box sizing, margins, padding, gaps
Style textFont family/size/weight/style, line height, alignment, text transform, letter spacing, line and word breaking, white-space: normal or pre-line
Decorate boxesColors, borders, rounded corners, background images, sizing, positioning, and repetition
Generate text::before, ::after, quoted content, attr(), counter(), counter reset and increment
Control pagesBare @page size/margins, print media rules, page breaks, and best-effort break-inside: avoid

Body lengths support pt, px, mm, cm, in, rem, supported percentages, and unitless 0. Letter spacing also accepts em. Flex and grid support gaps, alignment, ordering, and track/item sizing, but not every browser layout rule.

Render options

Pass options to HtmlToPdf.render(html, options) or render_file/3.

OptionUse it toDefaultSupported values
:page_sizeSet page dimensions:a4Named size, orientation tuple, size string, or numeric tuple. See page sizes.
:marginSet page margins0Nonnegative point number, CSS string, or side map. See margin formats.
:stylesheetsAdd CSS[]List of {:css, css} or {:file, path} entries
:base_urlAllow local images/fontsNoneDirectory path such as "priv/static". See asset sources.
:assetsMap asset references%{}Map of references to {:bytes, binary} or {:file, path}
:asset_resolverResolve asset referencesNoneOne-argument function or nil. See the callback contract.
:default_fontChoose text fonts"DejaVu Sans"Family name string or a list of family names in fallback order
:fontsRegister TrueType fonts[]List of font definitions with :family and :path or :data. See font registration.
:system_font_discoveryLook up installed fontstruetrue or false
:unsupported_glyphsHandle missing characters:replace:replace or :error
:formsCreate AcroForm fields:interactive:interactive or :static; see PDF forms.
:metadataSet document informationHTML title when presentMetadata fields such as :title and :author. See metadata options.
:outlinesAdd PDF bookmarksDisabled:headings, bookmark list, false, or nil. See bookmark examples.
:page_furnitureAdd headers and footersDisabledKeyword list or map of templates. See template options.

Page size and margins

Page-size formatSupported values or example
Named size:a5, :a4, :a3, :b5, :b4, :jis_b5, :jis_b4, :letter, :legal, :ledger
Named size with orientation{:a4, :landscape} or {:a4, :portrait}
Size string"a4 landscape" or custom dimensions such as "100mm 60mm"
Numeric {width, height}{8.5, 11} uses inches; {612, 792} uses points. Both values use inches when both are at most 20; otherwise both use points.

Prefer size strings with explicit units for custom dimensions.

Margin formatExampleMeaning
Point number3636 points on every side
CSS string with one value"12mm"Same margin on every side
CSS string with two values"18mm 12mm"Top/bottom, then left/right
CSS string with three values"18mm 12mm 10mm"Top, left/right, bottom
CSS string with four values"18mm 12mm 10mm 8mm"Top, right, bottom, left
Side map%{top: 36, bottom: "12mm"}Set individual sides; omitted sides are zero

Page-size and margin strings accept pt, px, mm, cm, in, q, and pc. Explicit :page_size and :margin options override @page.

Tables

FeatureSupport and limits
Column sizingAutomatic sizing or table-layout: fixed
Spanning cellscolspan and rowspan; a rowspan ends at its row-group boundary
Nested tablesSupported inside cells
BordersSeparate or collapsed borders; collapsed tables retain the requested bottom border at page breaks
Headers across pagesRows in <thead> repeat when the table continues on another page
Keeping row groups togetherSet break-inside: avoid on each <tbody> that should stay together; groups too tall for a page split between rows

Table page breaks

Page breaks use measured content height. The printable area is the page height minus its top and bottom margins.

  • <thead> repeats when a table continues onto another page and stays with the first body row when both fit. Body rows do not repeat.
  • Set break-inside: avoid on each <tbody> to keep its rows together. A group that fits on a fresh page with its heading moves there if needed. Larger groups split between rows. Without this CSS, groups can split even when they would fit on a fresh page.
  • With border-collapse: collapse, each page's final cells retain their configured bottom border. border-bottom: none remains absent.

A single row that cannot fit on a fresh page with its heading may overflow; this behavior does not split individual rows. Divide its content into multiple rows or reduce its height before rendering.

See the grouped table example.

Images and backgrounds

FormatSupported content
JPEGGrayscale, RGB, and CMYK
PNG8-bit, non-interlaced RGB/RGBA; transparency is supported. Chunk CRCs, required order, uniqueness, and critical chunk support are validated.
SVGSelf-contained SVG that does not load other images or external resources
Image stylingSupported values or behavior
object-fitfill, contain, or cover
object-positionPosition an image within its box
background-sizeExplicit sizes, cover, or contain
background-positionPosition a background within its box
background-repeatrepeat, repeat-x, repeat-y, or no-repeat

Assets and local files

SourceHow to supply itRules
Local directorybase_url: "priv/static" with src="images/logo.png"References are checked for traversal and symlinks beneath the directory. render_file/3 does not infer this directory.
Explicit asset mapassets: %{"logo.png" => {:bytes, bytes}} or a {:file, path} valueMappings take precedence; mapped files do not require :base_url.
Resolver callbackasset_resolver: fn request -> ... endUsed when a local reference fails path checks or cannot be read. Resource-limit failures do not fall back.
Data URIPut a supported data URI in the image referenceImage format restrictions still apply.

The resolver receives %{reference: reference, kind: kind}, where kind is :image, :background_image, or :font.

Resolver returnMeaning
{:ok, bytes}Use the supplied asset bytes
:not_foundThe resolver could not find the asset
{:error, reason}Asset resolution failed

The renderer never downloads remote assets itself. Caller-configured font paths and stylesheet files do not require :base_url. Local image and font reads through :base_url work on Windows, macOS, and Linux. Paths are checked for traversal and existing symlinks before bounded file reads. These checks cannot prevent another process from changing a path during a read. Use asset directories that untrusted users cannot modify, or supply approved bytes with :assets or :asset_resolver. Explicit file mappings, configured font paths, and stylesheet paths also use bounded reads and trust the caller's pathname.

See image and asset examples.

Fonts and text

Choose a font with CSS font-family or the :default_font render option.

Font sourceHow to use it
BundledDejaVu Sans is included and used by default.
Installed on the rendering machineSystem-font discovery is enabled by default. Use an installed family by name, such as font-family: "Liberation Sans" or default_font: "Liberation Sans", if that family is installed. No :fonts registration is needed.
Supplied by your applicationRegister a static TrueType font with :family and either :path or :data. Optional :weight and :style default to 400 and :normal.

Installed fonts must meet the same font-format and embedding requirements as supplied fonts. For consistent font selection across machines, supply your fonts and set system_font_discovery: false. See Register a font.

Missing characters use available fallback fonts, then U+FFFD replacement. Set unsupported_glyphs: :error to fail instead of replacing them.

Pagination

Pages break automatically or at supported CSS page breaks. Use :page_furniture for running headers, footers, and page numbers. Reserve enough margin for the templates; they do not push body content out of the way.

Templates can vary on the first, odd, and even pages. A matching false or nil variant hides that template. See headers and footers. For PDF viewer bookmarks, see outlines from headings.

Known limits

Not supportedWhat to use instead
JavaScript, canvas, video, audio, iframeStatic HTML and supported images
XFA, JavaScript form actions, password fieldsUse supported AcroForm fields or static artwork
Floats, fixed positioning, transforms, animationsBlock, flex, grid, relative, or absolute layout
Named pages and CSS page-margin boxesPage options and header/footer templates
CSS counter(page) or counter(pages){{page}} and {{pages}} in header/footer templates
Indexed, grayscale, 16-bit, or interlaced PNGRGB/RGBA PNG or JPEG
WOFF/WOFF2, variable fonts, CFF OpenTypeStatic TrueType fonts that permit embedding
Complex shaping or bidirectional textA renderer with shaping support for Arabic, Indic scripts, Thai, and complex emoji sequences

See Resource limits for configurable size limits and Browser rendering for visual tolerances.

JPEG color conventions

JPEG metadata preserves grayscale, RGB, YCbCr, ordinary CMYK, Adobe CMYK, and Adobe YCCK separately. Frame components and Adobe markers must be consistent. Unsupported component identifiers without an Adobe marker, conflicting markers, and repeated frames fail with a diagnostic. Ordinary CMYK keeps its sample polarity; Adobe CMYK and YCCK use inverted samples. The PDF writer emits explicit DCT color-transform parameters for the supported conventions.

The ordinary CMYK fixture contains standard non-inverted CMYK samples and no Adobe marker. It is independently rasterized alongside Adobe CMYK and YCCK. Some browser JPEG decoders assume inverted samples even without the Adobe marker, so browser decoding alone is not an oracle for ordinary CMYK polarity.

The mapping follows the Adobe PDF reference, section 3.3, DCTDecode filter parameters: https://opensource.adobe.com/dc-acrobat-sdk-docs/pdfstandards/pdfreference1.7old.pdf