v1 — react-ipynb-renderer
react-ipynb-renderer v1 was the first published release — a single React
component that rendered Jupyter .ipynb JSON into a read-only DOM tree.
The goal was modest but specific: let React apps drop a notebook into a
page without running a Jupyter server, without iframes, and without
server-side conversion.
Shape of the v1 API
One default export, one prop:
import { IpynbRenderer } from 'react-ipynb-renderer';
<IpynbRenderer ipynb={notebook} />Under the hood v1 did three things:
- Walk the
.ipynbJSON (both cell-array v4 and legacyworksheets[0].cells) and emit one React subtree per cell. - Run code cell sources through Prism for syntax highlighting,
matching the
metadata.kernelspec.language(or a best-effort guess). - Render outputs from the Jupyter MIME bundle:
text/plain,text/html,image/png,image/jpeg,image/svg+xml,text/latex.
Math rendering and interactive features didn’t exist yet — the component was a pure viewer.
Feature timeline
1.1.x — the HTML safety story
The big addition in 1.1 was the htmlFilter prop. Any notebook
exported from a Jupyter kernel can include arbitrary text/html in its
output (think pandas DataFrames, Plotly widgets, user-written display
calls). Without filtering, the renderer would pass that HTML straight
through, which is dangerous in apps rendering notebooks from untrusted
sources.
import DOMPurify from 'dompurify';
<IpynbRenderer ipynb={notebook} htmlFilter={(html) => DOMPurify.sanitize(html)}/>This was the first step toward making the renderer usable in
user-content-heavy apps (blog CMSs, teaching platforms), and the
htmlFilter prop survived all the way to v3 — it’s still part of
@jupyter-kit/core’s public API today.
1.2.x — formats and numbering
1.2 rounded out the output pipeline:
- SVG output (
output.svg) and raw image data started rendering correctly. Before 1.2, matplotlib figures exported as SVG would either be silently dropped or rendered as escaped text. - The language-name type was widened to accept
haskellandruby. The underlying Prism grammars had always been capable, but the TypeScript types gated them off. seqAsExecutionCountarrived — a flag controlling whether cells withexecution_count: nulldisplayIn [ ]:(classic Jupyter) or the positional indexIn [n]:. Useful for rendering in-progress notebooks that haven’t been fully re-run.
What worked well
- One install, one component. No plugin wiring, no optional bundles. Worked out of the box inside any React app.
- Presentational fidelity. The output section matched what Jupyter Lab itself showed for the same notebook — same line breaks, same colour-coded ANSI in tracebacks, same inline images.
What v1 couldn’t do
- No math rendering.
$...$/$$...$$passed through as raw text. - No theming. The component shipped a single stylesheet; if you wanted a different look you had to override CSS yourself.
- React-only. The component was the library; using the renderer from Vue or a plain HTML page meant re-implementing it.
Both limitations motivated v2.
Where to find v1 docs
The v1 documentation is archived at docs.walkframe.com/react-ipynb-renderer/history.
What survived into later versions
| v1 feature | Status in v3 |
|---|---|
htmlFilter prop | Unchanged — part of RendererOptions |
seqAsExecutionCount | Unchanged |
| SVG / raster image outputs | Unchanged |
| Prism highlighting | Replaced by Lezer — see the migration guide |
| Single React component | Still ships as @jupyter-kit/react, now thin over a framework-agnostic core |