Skip to main content

Display a notebook

notebook.view() returns a renderable view backed by a NotebookView. Browser evaluation starts when an anywidget host mounts it.

import marimo as mo
import observablejs as obs

notebook = obs.Notebook(
obs.js(
"""
const threshold = view(Inputs.range(
[0, 1],
{label: "Threshold", step: 0.05, value: 0.5}
));
""",
key="threshold",
),
obs.js(
'html`<p>Threshold: <strong>${threshold}</strong></p>`',
key="readout",
),
)

view = notebook.view()
view

Display in marimo and Jupyter

In marimo, use the returned view as a cell output or layout child. In JupyterLab, Jupyter Notebook, VS Code notebooks, and Google Colab, leave the view as the final cell expression or pass it to IPython.display.display.

Colab requires the third-party widget support described by anywidget.

One view per placement

One NotebookView can appear in one live location at a time. Create a separate view for each location.

chart_a = notebook.view("readout")
chart_b = notebook.view("readout")

mo.hstack([chart_a, chart_b])

The views receive the same notebook values and supported browser inputs. Each keeps its own rendered output, progress, results, errors, and graph.

Skip Python state capture

Use capture_state=False for a screenshot, preview, or embed when Python never reads view.state.

preview = notebook.view(
capture_state=False,
)
preview

The view still evaluates, renders, responds to input, and receives Python variable updates. Supported input controls continue to synchronize with other views from the same notebook. preview.state stays at its initial value.

With capture disabled, result serialization and transport are skipped. The avoided work grows with cell result size and update frequency, so small static views usually see little difference. Keep the default True when Python reads or observes view.state.

Evaluation lifecycle

Before display, both revision fields are None. Display starts revision 0 and sets pending=True. A revision finishes after every selected cell either succeeds or fails.

state = view.state
ready = (
not state.pending
and state.input_revision is not None
and state.settled_revision == state.input_revision
)

Python variable updates and browser inputs start a new revision when selected cells need to run again. Assigning a new theme restarts each open view. Create a new view for a different selection. Create a new notebook for a different cell definition or set of files. A restarted view clears its previous graph while work is pending.

Close views

view.close()
notebook.close()

view.close() stops one browser run and ignores any late results. notebook.close() closes every view created from that notebook. Repeated calls do nothing.

Cells that own browser resources should release them through Observable's invalidation promise:

obs.js(
"""
const controller = new AbortController();
invalidation.then(() => controller.abort());

const response = await fetch(dataUrl, {signal: controller.signal});
const records = await response.json();
"""
)

Continue with Select cells or Compose views.