Build plugins with anywidget!

Build plugins with anywidget!

If you’re new to marimo, check out our GitHub repo: marimo is free and open source.

At marimo, we give Python developers who work with data the tools they need to create their best work, starting with our next-generation reactive Python notebook. The marimo notebook is:

  • reactive: When a cell’s code changes, we re-run [1] all dependent cells (like Excel!). When a UI element changes, we re-run all cells consuming that UI element.
  • interactive: UI elements or “widgets” such as sliders, tables, and charts bring your data to life.

Widgets are a core part of what makes marimo so powerful. Traditional notebooks limit you to writing text and executing cells, but widgets extend this paradigm, allowing you to interact with your code and data in new ways. We are excited to share that we are standardizing our plugin API for widgets to be anywidget.

[1] By default, marimo re-runs all downstream cells, but it can be configured to be “lazy,” marking the cell as stale. This is useful for expensive notebooks.

Widgets in marimo

In marimo, widgets are a 2-way binding between your Python code and the browser. For example, a slider widget shows a draggable element in the frontend whose number value is obtainable in Python.

import marimo as mo
slider = mo.ui.slider(1, 10)
slider

The slider’s value can be accessed and reactively updated by simply calling slider.value (no callbacks required!).

slider

marimo’s built-in widgets use a custom internal API. With this API, we’ve developed over 20+ widgets that encompass the essential components needed for 95% of marimo notebooks. These widgets range from simple ones like text inputs, number inputs, and sliders to more complex ones like a tables, data explorer, and charts. We have also included widgets for layouting, such as tabs, accordions, or a sidebar.

However, we recognize that there’s a long tail of widgets our users need, many of which may not fit into the core library. These include domain-specific visualizations and other specialized functionalities. Predicting and maintaining all these specialized widgets would be highly challenging for marimo, so we aim to empower our ecosystem to create and share custom widgets.

We know that our community is constantly innovating, and we want to enable them to bring their innovations into marimo. That’s why we’re excited to announce that we’re standardizing on anywidget as our third-party plugin API. With anywidget, our users can create custom widgets that are limited only by their imagination.

anywidget provides a single interface for developing embeddable widgets inside other applications, such as Panel, Jupyter, and, of course, marimo. anywidget also comes with an excellent developer experience in creating these widgets with either vanilla JavaScript or popular frameworks like React and Svelte.

We’re excited about the possibilities of this new plugin API and look forward to seeing the innovative widgets our users will create!

anywidget today

marimo ships with native support for rendering anywidgets. Rendering an anywidget is as easy as:

from drawdata import ScatterWidget
 
widget = ScatterWidget()
widget

The magical part of using anywidget inside marimo is this: we make it seamless to automatically send anywidget values back to Python and trigger reactive execution. Just wrap your anywidget in mo.ui.anywidget:

+ import marimo as mo
  from drawdata import ScatterWidget
 
+ widget = mo.ui.anywidget(ScatterWidget())
  widget

Adding the marimo reactivity lets you bring anywidgets to life: downstream cells and visuals that depend on this widget will update automatically. For example, you can render a chart based on the selection of points created in the scatter widget:

# Early terminate if no data
mo.stop(not widget.data)
 
# Create a DataFrame from the widget data
df = pd.DataFrame(widget.data)
# Render a chart
chart = alt.Chart(df).mark_point().encode(x="x", y="y", color="color")

Building with anywidget

Building anywidgets is straightforward. Since anywidget is lightweight and aligns with modern browser standards, you can even build anywidget widgets inside the marimo playground. By building inside the playground, you can quickly prototype and test your widgets without setting up a Python environment or installing any dependencies. You can share a URL or embed the notebook or application in your website or blog post, as shown below:

Future work

In the future, our goal is to make this reactivity work without the need to wrap it in mo.ui.anywidget, and we aim to incorporate all API features supported by anywidget, including the new features under their experimental API.

Additionally, we plan to expand the functionality of these widgets beyond the cell’s output. Doing so will allow for integrating new plugin points, such as customized actions or a custom helper panel.

We’re working closely with the anywidget team: helping design and test new APIs, showcasing widgets in our WebAssembly playground (for compatible widgets), and contributing widgets back to the ecosystem.

Wrapping up

Plugin APIs are crucial for extensibility. They allow developers to expand a platform’s functionality without modifying its core code. Together with anywidget, marimo can enable a vibrant ecosystem of custom tools and features that cater to diverse user needs.

We believe anywidget’s API is best served in a reactive environment, and we are thrilled to officially support anywidget and bring its growing community into the marimo ecosystem!

Learn more about anywidget: site, discord, github_

Join the marimo community

If you’re interested in helping shape marimo’s future, here are some ways you can get involved: