Anywidget: Custom Jupyter Widgets Made Easy

0.10.0 · active · verified Sat Apr 11

Anywidget is a Python library that dramatically simplifies the process of creating custom interactive widgets for computational notebooks, running in environments like Jupyter, JupyterLab, Google Colab, VS Code, and Marimo. It's both a specification and a toolkit, allowing developers to define widget front-end code using standard ECMAScript modules (ESM) within a Python class. Currently at version 0.10.0, it features a rapid release cadence with frequent updates.

Warnings

Install

Imports

Quickstart

This example defines a simple counter widget using `anywidget.AnyWidget`. It includes both Python (`traitlets.Int`) and JavaScript (`_esm`) components. The JavaScript code defines how the widget renders and interacts with the Python backend, including handling button clicks and updating a synchronized `count` traitlet. The `initialize` and `render` lifecycle hooks are the preferred way to define the frontend logic since v0.9.

import anywidget
import traitlets
from IPython.display import display

class CounterWidget(anywidget.AnyWidget):
    _esm = """
    export default {
        initialize({ model }) {
            // Optional: run once per widget instance
            console.log('Widget initialized');
        },
        render({ model, el }) {
            let getCount = () => model.get('count');
            let button = document.createElement('button');
            button.innerHTML = `count is ${getCount()}`;

            button.addEventListener('click', () => {
                model.set('count', getCount() + 1);
                model.save_changes();
            });

            model.on('change:count', () => {
                button.innerHTML = `count is ${getCount()}`;
            });
            el.appendChild(button);

            return () => {
                // Optional: cleanup on view removal
                button.removeEventListener('click', () => {});
            };
        }
    };
    """
    _css = """ button { padding: 5px 10px; border-radius: 5px; background-color: #f0f0f0; } """
    count = traitlets.Int(0).tag(sync=True)

widget = CounterWidget()
display(widget)
# You can also interact with the widget from Python
# widget.count = 5 # This will update the frontend

view raw JSON →