Self-contained HTML

A self-contained HTML file inlines every stylesheet, script, font and image into the document itself — as <style> and <script> blocks and data: URIs — so it renders correctly with no sibling directory and no network access. Also called standalone, single-file or embedded-resource HTML.

It exists because the default output of most report generators is a directory, and directories do not survive being emailed, dropped into a chat, or attached to a ticket.

How to produce one

Tool Flag
Pandoc --embed-resources --standalone
Jupyter nbconvert --to html --embed-images
Quarto --embed-resources (or embed-resources: true)
Plotly include_plotlyjs="inline", full_html=True
Bokeh file_html(plot, INLINE)
R Markdown self_contained: true (the default)
Vega / Altair chart.save("x.html", inline=True)

Tools without a flag — Allure, most coverage reporters, Storybook — are not oversights. Their reports are architecturally multi-file: a shell that fetches a JSON tree at runtime. Inlining a tree of thousands of per-test JSON files into one document is not a flag, it is a rewrite.

The size tax

Base64 encoding inflates binary data by roughly 33%, and inlining defeats every browser optimisation that made the multi-file version fast:

  • Nothing is cached between loads. Every open re-downloads everything.
  • Nothing is lazy. Images below the fold parse with the rest.
  • The parser blocks on the whole document before first paint.

A report that was a 400 KB entry file plus 6 MB of assets becomes an 8 MB single file that takes seconds to open and will not attach to most mail servers (too big to email).

What it fixes, and what it doesn't

Fixes: missing CSS, dead scripts, broken images, 404s on click-through — everything caused by the entry file travelling alone.

Does not fix:

  • Attachment size limits, which it usually makes worse.
  • Chat clients that refuse to preview HTML for security reasons (why Slack won't).
  • The reader's file:// origin, which still blocks any runtime fetch() the page does (same-origin policy).
  • Comments, versions, and knowing whether anyone opened it.

Self-contained HTML solves a packaging problem. Sending someone a file and hoping remains a delivery problem.

The alternative to packaging

Publish the directory as it is. Assets upload alongside the entry HTML with relative references rewritten to the uploaded copies, so nothing needs inlining, nothing inflates by a third, and the recipient gets a URL instead of an attachment — one that renders on a phone, in a ticket preview, and behind a corporate proxy.

Limits: entry HTML 5 MB; assets 25 MB per file, 250 MB and 500 files per report. Single-file exports that exceed 5 MB are almost always inlined assets, which is the case where uploading the original directory is both smaller and faster.

Try it

Comma is free — unlimited reports, unlimited commenters, unlimited revision history.

Publish a report directory →

Related