Upstreaming `anywidget` into the MyST Markdown core
If you’ve seen my posts on the SeqViz Plugin or Visualizing OME Microscopy Data with Vizarr, you’ve seen how we can use the any:widget[1] directive in Curvenote to bring rich, interactive content into posts, articles, etc...
Right now I’m in the middle of upstreaming our implementation into the core Myst Markdown stack. Why? and what does this mean?
Because it’s how I/we can best contribute to the MyST ecosystem; experiment and develop ideas where we wan move fast, then upstream the useful bits, consolidating, improving and expanding on the way
We want to expand the capabilities, build out the full AnyWidget interface contract and doing that upstream means more upside for the whole community
Having more people involved will better steer the interface directive and AST representation to fit diverse use cases
And having it in the core of
mystmdmeans it’ll be maintained and can be relied on by MyST Markdown usersOne more big technical step up in this is the
anywidget[2] will gain first-class representation in the AST{ "type": "anywidget" }rather than overloadingblock[kind][3].
For folks with content using this on Curvenote, don’t worry the previous directive will keep working even after we’ve transitioned to the core MyST implementation.
This post outlines where things stand, what the first cut will ship, and what’s coming next—plus a small, fun example you can try.
A quick example: a div-map widget¶
The example-widgets repo is the test bed for the new directive. One of the modules is a tiny “div-map”: a heatmap-style grid rendered from an array-of-arrays of numbers, with configurable color schemes (mono, reds, blues, greens). The module is hosted at curvenote
A live div-map heatmap rendered by the {anywidget} directive using the hosted divmap module. The directive takes the ESM URL and a JSON body of props (colors, data).
Just as before directive takes a URL to an ESM JavaScript module and a JSON body of props. The widget runs in the browser, so you get interactive figures without rebuilding the theme—same idea as the SeqViz Plugin and Vizarr posts, but as a built-in MyST feature.
A short video walkthrough of testing with the example-widgets repo is posted on the theme PR (PR #795).
What’s in the first cut¶
In mystmd (PR #2602): A new core
{anywidget}directive and a first-class AST node (anywidget). The directive is part of the mystmd stack (not a plugin), so it parses consistently everywhere. You specify the ESM URL as the argument, optional:class:and:css:(and future:static:) as options, and a JSON/JSON5 body for widget props; the parser emits a typedanywidgetnode.In myst-theme (PR #795): A dedicated anywidget package and node renderer that loads the ESM from the URL and passes the JSON into the widget. Rendering works today; the full AnyWidget front-end model (e.g. named models, two-way sync) is planned for a follow-up.
So the first cut is: author widgets in Markdown with {anywidget} and have them render from hosted JS modules with data passed in. No theme rebuild required.
What’s coming next¶
The tracking issue (mystmd #2603) spells out the longer roadmap. Planned extensions include:
Local modules: Point at a local ESM (and CSS) in the project and have the build serve it (with optional transform for copying and URL rewriting).
Baking in remote modules: Pull remote ESM (and CSS) into the build so the published site doesn’t depend on an external URL.
Static assets: Let a widget declare extra static assets (e.g. PNG, SVG) to ship with the site.
Full AnyWidget front-end model: Named model instantiation and the full sync cycle so multiple widgets can communicate (e.g. an acceptance test analogous to the AnyWidget Counter example).
There are also open questions (e.g. inline _esm/_css vs. file-based modules, and how to handle “hardcopy” fallbacks for widgets).
Summary¶
Initiative: mystmd #2603 — support the anywidget standard so arbitrary JS can be used in a bounded way via
widgetnodes.Parser/directive: mystmd PR #2602 —
{widget}/{anywidget}directive first pass.Theme renderer: myst-theme PR #795 — anywidget directive support and testing video.
Example repo: jupyter
-book /example -widgets — confetti, div-map, and Vizarr-style examples for development and testing.
Once these PRs land, you’ll be able to drop widgets like the div-map (and eventually full Vizarr-style viewers) into any MyST book or article using the same directive, without custom theme code.
Once the native {anywidget} directive is released in mystmd and myst-theme, the Curvenote stack will also support it. Content using the existing Curvenote any-widget extensions can adopt the same directive syntax, and Curvenote-published sites will render the native directive so you get one consistent way to embed widgets across the MyST and Curvenote ecosystems.
Copyright © 2026 Purves. This is an open-access article distributed under the terms of the Creative Commons Attribution 4.0 International license, which enables reusers to distribute, remix, adapt, and build upon the material in any medium or format, so long as attribution is given to the creator.