What is anywidget?
Updated
anywidget is a lightweight standard for building reusable interactive widgets in notebook environments. You define a widget as a Python class (using traitlets) plus a JavaScript render function, and anywidget handles the wiring between them. It's aimed at people who want portable widgets that stay compatible with the existing ecosystem rather than being locked to one framework. If you work in Jupyter-style notebooks and want a small, reusable interactive component, it's relevant to you.
The core idea
The project describes itself as "reusable widgets made easy" and frames its goal as going "beyond frameworks" to offer a widget standard — a portable way to define widgets while maintaining ecosystem compatibility.
In practice, a widget is two pieces:
- A Python class that holds state as
traitletsand declares which traits sync to the front end. - A JavaScript
renderfunction (embedded as an ESM string) that builds the DOM and reacts to model changes.
anywidget connects the two: trait changes propagate to JavaScript, and JavaScript can push changes back to Python.
A minimal example
The site's example is a counter widget. The Python side:
import anywidget
import traitlets
class CounterWidget(anywidget.AnyWidget):
_esm = """
function render({ model, el }) {
let count = () => model.get("count");
let btn = document.createElement("button");
btn.innerHTML = `count is ${count()}`;
btn.addEventListener("click", () => {
model.set("count", count() + 1);
model.save_changes();
});
model.on("change:count", () => {
btn.innerHTML = `count is ${count()}`;
});
el.appendChild(btn);
}
export default { render };
"""
count = traitlets.Int(0).tag(sync=True)
What each part does:
_esmholds the JavaScript that renders the widget. Therenderfunction receives{ model, el }—elis the container to append to,modelis the synced state.model.get("count")reads the current value;model.set(...)followed bymodel.save_changes()writes it back to Python.model.on("change:count", ...)re-runs your handler when the value changes, so the UI stays in sync.count = traitlets.Int(0).tag(sync=True)declares the trait and marks it for two-way sync.
Using it in a notebook:
from mywidget import CounterWidget
counter = CounterWidget()
counter
Then counter.count reads the current value from Python.
When to use it
anywidget fits when you want:
- A reusable widget packaged as a normal Python module, not a one-off notebook cell.
- Portability across notebook environments rather than a dependency on a specific widget framework.
- A small surface area — a Python class and a JS render function, with sync handled for you.
It's less about providing a large library of prebuilt widgets and more about giving you a standard to build your own on.
Getting started
The entry point shown on the site is:
pip install anywidget
From there, the pattern is: create a module (e.g. mywidget/__init__.py), define an AnyWidget subclass with an _esm string and synced traits, then import and instantiate it in a notebook. The site's demo runs in a notebook at localhost:8888/Demo.ipynb.
For background on the design goals, the site references a SciPy 2024 talk, "Beyond Frameworks, a Widget Standard," about how anywidget sets a standard for portable widgets while maintaining ecosystem compatibility.