Published
Modified

Can we build a reactive article in a single HTML file?

Yes (by standing on the shoulders of Observable).

Before I start, why am I doing this?

I don't think HTML is being used enough as a platform for scientific publishing.

Instead, people will:
  1. First use an interactive notebook like Jupyter, Pluto.jl or Observable to do data exploration, analysis and visualisation,
  2. Then move to publishing platforms like Quarto, Typst, Overleaf, pure LaTeX, or a WYSIWYG editor to typeset their work.

I think self-contained HTML files can be used for both of these stages, and prevent a lot of faffing around with CLI tooling, CI steps, or 3rd-party platforms.

HTML's typesetting capabilities are well documented, but its capabilities as a platform for data exploration, analysis and visualisation are not.

I'll try and demonstrate these capabilities, literate programming style.
A computer displays an open book

Cells

First, we'll steal a trick from This page is a truly naked, brutalist html quine, and create a CSS class called echo that will display/reflect style and script elements inline. This style block has effectively styled itself. Now we'll import the Observable standard library and the Observable runtime, and bind them to window. We'll define helper methods cell and observer that wrap some of the runtime API. Now we'll declare a cell called counter that emits a number every second. The script's id attribute is the same as the name parameter passed to cell. Now that we've created a our counter cell, we can create other cells that depend on it.
We'll import Hypertext Literal and use it to format the counter value. We'll import Observable Plot and use the counter value in the plot. We should always store data in their own script elements, so that they can be easily referenced by other cells.
A computer displays a graph in the upward direction

Inputs

We'll create a new cell type viewof that works specifically with Observable Inputs. It declares 2 reactive cells: NAME and viewof NAME - one for the value, and one for the DOM element itself. Wiggle the range input and see another dependent cell update.

Mutability

Purely functional dataflow is great, but sometimes you just need to mutate state. We'll create a new cell type mutable. It registers a Mutable - an object that yields new Generator values when the value is mutated - in the runtime.

TeX, Markdown, Graphviz

What's the point otherwise?
A computer with an open CD tray is surrounded by data

SQLite

I've hosted the Chinook sample database on my website at https://maxbo.me/chinook.db. Now we'll use a WASM-backed SQLite client to query it.

Python

The Pyodide CPython WASM distribution includes NumPy, Pandas, Matplotlib, scikit-learn, and Scipy. We'll rebuild the plot seen above, but using Matplotlib and Python's sqlite3 module instead.

R

You know the drill. It's R, using WebR. I didn't figure out how to get ggplot2 rendering working, but I assume it's possible. I must disclose that this cell seems to be a bit flaky on iOS. I have not had a chance to investigate further, nor will I.

3D models

We can use Google's <model-viewer> Web Component to display 3D models.

Cell status

Observable's Inspector can apply an observablehq--running or observablehq--error class to the cell's div result element. We'll style them appropriately:

What's next?

I will try and cram all of this into a library with some proper documentation. Stay tuned.
A computer terminal receives text