Marimo Notebooks

Great Docs can embed interactive Marimo notebooks directly in your documentation pages. Readers run code examples live in their browser (no installation required) powered by WebAssembly (Pyodide). They can also copy the notebook source to run locally with marimo edit.

There are two ways to embed a notebook, and they make different trade-offs:

Pick island mode to show a live result, and pick iframe mode to let readers rewrite it.

How It Works

Marimo notebooks are Python files with @app.cell decorators. What Great Docs does with them at build time depends on the mode.

Island mode uses the @marimo-team/islands runtime:

  1. Reads the .py notebook at build time
  2. Extracts each cell and emits <marimo-island> HTML elements
  3. On page load, the islands runtime boots a Pyodide kernel in the browser
  4. mo.ui widgets become interactive and changing a widget re-runs the cells that depend on it

The code editors in island mode are for display only. Editing the source text does not re-execute. Reactivity flows from the UI controls, not from edits to the code.

Iframe mode self-hosts a full WASM export:

  1. Runs marimo export html-wasm --mode edit on the notebook at build time
  2. Bundles the result as static assets and embeds it in a sandboxed <iframe>
  3. The notebook boots and auto-runs on load, so readers land on live outputs
  4. Every cell is editable: edit, press Ctrl+Enter, and dependents re-run

Either way there’s zero backend infrastructure: everything runs in the reader’s browser.

Quick Start

Getting a live notebook onto your documentation page takes three steps: enable the feature, create a notebook, and drop in a shortcode. Here’s each step in detail.

1. Enable marimo in great-docs.yml

marimo: true

Or with explicit version pinning:

marimo:
  enabled: true
  version: "0.23.7"

Iframe mode additionally needs uv available at build time (marimo uses it to resolve the notebook’s dependencies for the WASM export). Installing the marimo extra brings it in:

pip install "great-docs[marimo]"

2. Create a notebook

Marimo notebooks are standard Python files. Create a notebook in a notebooks/ directory (or anywhere in your project):

marimo edit --sandbox notebooks/my-demo.py

The --sandbox flag inlines package dependencies as PEP 723 metadata, ensuring they install automatically in the WASM environment.

3. Embed with the shortcode

In any .qmd page:

{{{< marimo file="notebooks/my-demo.py" >}}}

Once you render the site, the notebook cells appear inline with live outputs and interactive widgets. To make the code itself editable, add mode="iframe" (see below).

Island Mode

Island mode is the default. The notebook’s cells render inline in the page, in the natural flow of your prose (outputs and mo.ui() widgets are live, while the code is shown for reference only). It’s the lightweight way to drop a live result into a paragraph.

{{{< marimo file="notebooks/reactive-intro.py" >}}}

Here’s a small notebook embedded this way. Drag the sliders and watch the summary, bar chart, and table all recompute together. The dependent cells re-run reactively, with no “Run” button to press:

Initializing...
Run locally: marimo edit reactive-intro.py

The Pyodide runtime loads lazily (only when the notebook scrolls into view) so it doesn’t slow down initial page load. The following example uses only marimo (no third-party packages), so the kernel boots quickly and reliably. It’s a good default for a live demo (see Writing WASM-compatible notebooks).

NoteIsland-mode code is read-only

The code above runs, but editing it won’t re-execute (island mode keeps the outputs interactive while showing the code for reference). When you want readers to edit and re-run the code itself, use iframe mode instead.

ImportantOne island notebook per page

All island embeds on a page share a single Pyodide kernel, and marimo requires every variable to be defined in exactly one cell across that kernel. Two island notebooks on the same page therefore collide and break each other’s reactivity. Aim to embed at most one island notebook per page. if you need several live notebooks together, use iframe mode, which isolates each notebook in its own kernel.

Outputs only

Pass show-code="false" to hide the source and show only the rendered outputs. This is useful for dashboard- or app-style presentations where the code is secondary:

{{{< marimo file="notebooks/reactive-intro.py" show-code="false" >}}}

Iframe Mode

Iframe mode embeds the notebook as a fully editable, reactive environment in a sandboxed iframe. This is the mode to use when you want to encourage experimentation with the code. Because each iframe is its own isolated kernel, it’s also the preferred method for placing several live notebooks on one page.

{{{< marimo file="notebooks/reactive-intro.py" mode="iframe" height="600px" >}}}

The notebook auto-runs on load, so readers see live outputs immediately, and every cell is editable. Edit a cell and press Ctrl+Enter to re-run it (dependent cells will update automatically). Here’s the same notebook from above. It’s now fully editable so try changing the chart-drawing code or the slider ranges:

By default the editor chrome is trimmed (marimo’s sidebar and status bar are hidden) to keep the embed clean. Use chrome="full" if you’d like to provide the complete editor interface. The iframe also auto-sizes to fit the notebook, so it grows to hold all your cells and re-adjusts when reactive outputs change size. The height parameter sets the initial height while the notebook loads.

Shortcode Options

The {{< marimo >}} shortcode accepts several options that control how the notebook is rendered and how readers interact with it.

Option Default Applies to Description
file (required) both Path to the .py marimo notebook (relative to project root)
mode "island" both "island" for inline WASM cells, "iframe" for a full editable notebook
show-code "true" island Show source code alongside output
show-copy "true" island Display the “Copy Notebook” button
theme "auto" both Color theme: "auto", "light", or "dark"
height "600px" iframe Initial height. The iframe then auto-sizes to fit the notebook
chrome "trimmed" iframe "trimmed" hides marimo’s editor sidebar/status bar while "full" shows the complete editor

You can combine these options to suit your needs. For instance, you might use show-code="false" with theme="dark" for a polished island-mode demo, or mode="iframe" with a custom height for a full-featured exploratory tool.

Writing WASM-Compatible Notebooks

Because notebooks run in the browser via Pyodide, there are some differences from a standard Python environment. Not all packages work in WebAssembly, and memory is limited. The guidelines below will help you author notebooks that run reliably for your readers.

Supported packages

All packages with pure Python wheels on PyPI work, plus many compiled packages bundled with Pyodide: NumPy, SciPy, pandas, Polars, scikit-learn, Matplotlib, Plotly, and more. See Pyodide’s package list.

The catch is compiled packages that aren’t in Pyodide and don’t ship a WASM wheel. These fail to install in the browser with an error like Can't find a pure Python 3 wheel for '<pkg>'. The ecosystem is moving toward publishing emscripten/WASM wheels under PEP 783, so these pins should become unnecessary over time.

Best practices

The following tips may be useful when setting up a Marimo notebook:

  1. Use --sandbox when authoring: marimo edit --sandbox notebook.py
  2. Put import marimo as mo in its own cell: this speeds up initial rendering
  3. Keep notebooks lightweight: WASM has a 2 GB memory limit
  4. Use mo.notebook_location() for data file paths that work both locally and in WASM
  5. Test in browser: export with marimo export html-wasm notebook.py -o test/ and serve with python -m http.server -d test/

Including data files

Place data files in a public/ folder next to your notebook:

notebooks/
├── reactive-intro.py
└── public/
    └── sample-data.csv

Access them portably:

import marimo as mo

path = mo.notebook_location() / "public" / "sample-data.csv"

Following these guidelines ensures your notebooks work consistently across local development and the browser-based WASM environment your readers will use.

Copy Notebook

Every embedded island-mode notebook includes a Copy Notebook button. Readers can copy the full .py source and run it locally:

# Install marimo
pip install marimo

# Run the copied notebook
marimo edit reactive-intro.py

The button copies the complete notebook source including the PEP 723 dependency metadata, so marimo edit --sandbox will auto-install all required packages.

Performance Notes

Interactive notebooks add weight to a page, but several optimizations keep the experience smooth for readers. Here’s what to expect:

  • Pyodide weighs ~15 MB on first load (cached by the browser afterward)
  • Lazy loading: in island mode the WASM kernel only boots when the notebook scrolls into view
  • Single kernel per page: multiple island-mode {{{< marimo >}}} shortcodes share one Pyodide instance
  • Iframe mode boots its own kernel per embed, since each iframe is a self-contained notebook
  • First execution takes 3–5 seconds while packages install whereas subsequent runs are fast

For pages where instant rendering matters, consider providing a static screenshot or pre-rendered output above the interactive notebook as a visual anchor while Pyodide loads.

Limitations

While Marimo notebooks offer a powerful interactive experience, there are some constraints imposed by the browser-based execution environment. The table below summarizes the key limitations and suggested workarounds.

Limitation Workaround
Not all packages available Stick to Pyodide-supported or pure-Python packages and pin around compiled deps (see above)
2 GB memory cap Keep datasets small and use aggregated data for demos
No threading/multiprocessing Use single-threaded patterns
~15 MB initial download Browser caches aggressively while lazy-load defers cost
No PDB debugging Use print() or mo.output for debugging
Island-mode code is read-only Use mode="iframe" when readers should edit the code
One island notebook per page (shared kernel) Embed at most one island notebook per page; use mode="iframe" for multiple live notebooks

For most documentation use cases (small datasets, pure-Python packages, and focused examples) these limitations won’t be an issue. Design your notebooks around concise, self-contained demonstrations and the experience will be seamless.

Next Steps

Now that you have interactive notebooks embedded in your documentation, here are some ways to build on it:

  • Marimo docs: Learn about reactive programming, UI elements (mo.ui.slider, mo.ui.dropdown), and layout tools to make your notebooks more interactive.
  • Add interactivity: Use mo.ui widgets to let readers explore data with sliders, dropdowns, and toggles. All reactive by default, so outputs update the moment a value changes.
  • Let readers edit the code: Use mode="iframe" on the examples where experimenting the code is emphasized (you get a fully editable, reactive notebook right in the page).
  • Check WASM compatibility: Run marimo export html-wasm notebook.py -o test/ locally to verify your notebook works in the browser before publishing.
  • Marimo gallery: Browse examples of dashboards, explorable explanations, and interactive tutorials you can adapt for your own documentation.

With Marimo notebooks, your documentation goes beyond static code examples. Readers can experiment with your package directly in the browser, building intuition through hands-on exploration.