a post with marimo notebooks

marimo is a reactive Python notebook that runs in the browser via WebAssembly. You can embed interactive marimo notebooks directly in your blog posts — readers can run and edit Python code without installing anything.

al-folio supports two ways to embed marimo notebooks:

  1. Inline snippets — write Python code directly in your post that becomes interactive
  2. Iframe embeds — embed hosted marimo notebooks from marimo.app

Inline marimo snippets

The simplest approach is to write Python code blocks directly in your post. When marimo: true is set in the frontmatter, the marimo-snippets library is loaded automatically and converts your code blocks into interactive notebooks running via WebAssembly.

Wrap your code in a <div> with class marimo-notebook-inline and markdown="1". Each fenced code block becomes a separate cell in the notebook:

<div class="marimo-notebook-inline" markdown="1">

```python
import marimo as mo
```

```python
name = mo.ui.text(placeholder="your name", label="Enter your name:")
name
```

```python
mo.md(f"Hello, **{name.value or 'stranger'}**! 👋") if name.value else mo.md("Type your name above!")
```

</div>

This produces the following interactive notebook — type your name and see the greeting update in real time! Powered entirely by WebAssembly in your browser, no server needed:

import marimo as mo
name = mo.ui.text(placeholder="your name", label="Enter your name:")
name
mo.md(f"Hello, **{name.value or 'stranger'}**! 👋") if name.value else mo.md("Type your name above!")

Merging code blocks with markdown cells

You can also include markdown cells alongside Python cells:

<div class="marimo-notebook-inline" data-height="600px" markdown="1">

```md
# Introduction

You can also add markdown cells to your notebooks.
```

```python
import marimo as mo
```

```python
slider = mo.ui.slider(1, 10)
slider
```

```python
slider.value * "🍃"
```

</div>

Result:

# Introduction

You can also add markdown cells to your notebooks.
import marimo as mo
slider = mo.ui.slider(1, 10)
slider
slider.value * "🍃"

A convex optimization demo

Here’s a more advanced example using cvxpy to solve a convex optimization problem with a live visualization. The Chebyshev center of a polygon is the center of the largest circle that fits entirely inside it — a classic problem in computational geometry. Move the slider to shift the right wall and watch the optimal inscribed circle adapt:

import marimo as mo
mo.md(
    r"""
**Chebyshev Center** — Given a polygon defined by half-planes $a_i^\top x \leq b_i$, find the largest inscribed circle:

$$\text{maximize} \quad r \qquad \text{s.t.} \quad a_i^\top x_c + \lVert a_i \rVert_2 \, r \leq b_i \;,\; i = 1, \dots, m$$
"""
)
wall = mo.ui.slider(start=1.5, stop=5.0, step=0.1, value=3.5, label="Right wall position:")
wall
import cvxpy as cp
import numpy as np
import matplotlib
matplotlib.use("agg")
import matplotlib.pyplot as plt

w = wall.value

# Polygon as half-planes: Ax <= b
# x >= 0, y >= 0, y <= 3, x + y <= 5, x <= w
A = np.array([[-1, 0], [0, -1], [0, 1], [1, 1], [1, 0]])
b = np.array([0.0, 0.0, 3.0, 5.0, w])

# Chebyshev center: maximize radius of inscribed circle
r = cp.Variable(nonneg=True)
xc = cp.Variable(2)
prob = cp.Problem(
    cp.Maximize(r),
    [A[i] @ xc + np.linalg.norm(A[i]) * r <= b[i] for i in range(len(b))],
)
prob.solve()

# --- Visualization ---
fig, ax = plt.subplots(figsize=(7, 5))

# Shade the feasible polygon
gx = np.linspace(-0.5, 6, 250)
gy = np.linspace(-0.5, 4, 250)
xx, yy = np.meshgrid(gx, gy)
pts = np.column_stack([xx.ravel(), yy.ravel()])
feasible = np.all(pts @ A.T <= b + 1e-9, axis=1).reshape(xx.shape)
ax.contourf(xx, yy, feasible.astype(float), levels=[0.5, 1.5], colors=["#3b82f6"], alpha=0.15)
ax.contour(xx, yy, feasible.astype(float), levels=[0.5], colors=["#3b82f6"], linewidths=2)

# Draw the largest inscribed circle
if prob.status in ("optimal", "optimal_inaccurate"):
    circle = plt.Circle(xc.value, r.value, fill=False, color="#ef4444", lw=2.5, ls="--")
    ax.add_patch(circle)
    ax.plot(*xc.value, "o", color="#ef4444", ms=9, zorder=5)
    ax.annotate(
        f"r* = {r.value:.2f}",
        xy=xc.value,
        xytext=(15, 15),
        textcoords="offset points",
        fontsize=12,
        color="#ef4444",
        fontweight="bold",
        arrowprops=dict(arrowstyle="->", color="#ef4444"),
    )

ax.set_xlabel("$x_1$", fontsize=13)
ax.set_ylabel("$x_2$", fontsize=13)
ax.set_title("Chebyshev Center — Largest Inscribed Circle", fontsize=14, fontweight="bold")
ax.set_aspect("equal")
ax.grid(True, alpha=0.3)
ax.set_xlim(-0.5, 6)
ax.set_ylim(-0.5, 4)
plt.tight_layout()
fig

note: The code can be shown by going to the three dots menu on the top right of the notebook and selecting “Show code”. You can also set data-show-code="true" on the container div to show code by default.

Iframe embeds

For more complex notebooks, you can host them on marimo.app and embed them via iframe using the marimo.liquid include:

{% include marimo.liquid src="https://marimo.app/l/YOUR_NOTEBOOK_ID" %}

Here is a hosted notebook from the marimo team:

A hosted marimo notebook

You can also customize the embed:

{% include marimo.liquid src="https://marimo.app/l/YOUR_NOTEBOOK_ID" height="800px" mode="edit" caption="My interactive notebook" %}

Include parameters

Parameter Default Description
src URL of the hosted marimo notebook (required)
height "600px" Height of the iframe
width "100%" Width of the iframe
mode "read" "read" (read-only) or "edit" (editable)
embed true Append embed=true query parameter
caption Caption text displayed below the notebook
title Accessible title for the iframe
class Additional CSS classes

Setting up your own post

To add marimo notebooks to your blog post:

  1. Add marimo: true to your post’s frontmatter — this loads the marimo-snippets library
  2. For inline snippets, wrap Python code blocks in <div class="marimo-notebook-inline" markdown="1">
  3. For iframe embeds, use {% include marimo.liquid src="..." %}

That’s it! Your readers get a fully interactive Python environment right in their browser.




Enjoy Reading This Article?

Here are some more articles you might like to read next:

  • Google Gemini updates: Flash 1.5, Gemma 2 and Project Astra
  • Displaying External Posts on Your al-folio Blog
  • a post with plotly.js
  • a post with image galleries
  • a post with tabs