Ui

UI Elements

One of marimo’s most powerful features is its first-class support for interactive user interface (UI) elements: interacting with a UI element will automatically run cells that reference it. ## marimo.ui

The marimo.ui module has a library of pre-built elements. For example, here's a slider: and here's its value: 1.

How interactions run cells

Whenever you interact with a UI element, its value is sent back to Python. When this happens, all cells that reference the global variable bound to the UI element, but don’t define it, will run.

This simple rule lets you use UI elements to drive the execution of your program, letting you build interactive notebooks and tools for yourselves and others.

Interacting with a displayed UI element will only trigger reactive execution if the UI element is assigned to a global variable.
Every UI element has a value attribute that you can access in Python.
You can embed UI elements in markdown using f-strings. For example, we can render the slider here:

Simple elements

marimo has a large library of simple UI elements:

Composite elements

Composite elements are advanced elements let you build UI elements out of other UI elements. Use these powerful elements to logically group together related elements, create a dynamic set of UI elements, or reduce the number of global variables in your program. Select a composite element:

State

You can build powerful interactive notebooks and apps using just mo.ui and reactivity.

Sometimes, however, you might want interactions to mutate state. Maybe you’re building a checklist, and you want to maintain a list of action items. Or maybe you want to tie two different UI elements, so that updating one updates the other.

For these and other cases, marimo provides the function mo.state, which creates state returns a getter function and a setter function. When you call the setter function in one cell, all other cells that reference the getter via a global variable are automatically run (similar to UI elements).

def state(value: T, allow_self_loops: bool = False) -> tuple[State[T],
  Callable[[T], None]]: 
Mutable reactive state This function takes an initial value and returns:
  • a getter function that reads the state value
  • a setter function to set the state's value
When you call the setter function and update the state value in one cell, all other cells that read any global variables assigned to the getter will automatically run. By default, the cell that called the setter function won't be re-run, even if it references the getter; to allow a state setter to possibly run the caller cell, use the keyword argument allow_self_loops=True. You can use this function in conjunction with UIElement on_change handlers to trigger side-effects when an element's value is updated. For example, you can tie multiple UI elements to derive their values from shared state. Basic Usage. Create state:
get_count, set_count = mo.state(0)
Read the value:
get_count()
Update the state:
set_count(1)
Update the state based on the current value:
set_count(lambda value: value + 1)
Note: Never mutate the state directly. You should only change its value through its setter. Synchronizing multiple UI elements.
get_state, set_state = mo.state(0)
# updating the state through the slider will recreate the number (below)
slider = mo.ui.slider(0, 100, value=get_state(), on_change=set_state)
# updating the state through the number will recreate the slider (above)
number = mo.ui.number(0, 100, value=get_state(), on_change=set_state)
# slider and number are synchronized to have the same value (try it!)
[slider, number]
Warning. Do not store marimo.ui elements in state; doing so can lead to hard-to-diagnose bugs. Args:
  • value: initial value of the state
  • allow_self_loops: if True, if a cell calls a state setter and also references its getter, the caller cell will be re-run; defaults to False.
Returns:
  • getter function that retrieves the state value
  • setter function that takes a new value, or a function taking the current value as its argument and returning a new value

Creating state

mo.state takes an initial state value as its argument, and returns

  • a function that returns the state value;
  • a function that updates the state value.

For exaxmple,

get_counter, set_counter = mo.state(0)
Calling a state's setter function will only trigger reactive execution if the corresponding getter is assigned to and referenced via a global variable.
You can get far using just mo.ui, without state. That said, judiciously using state can simplify the implementation of highly interactive notebooks/apps, and also enables new use cases.
Access the value of the state via its getter: get_counter() returned 0

Setting State

Set an element’s state by calling its setter function.

  • Call it with a new value: set_counter(1)
  • Call it with a function that takes the current value and returns a new one: set_counter(lambda count: count + 1)

State updates are reactive. When you call a state’s setter in one cell, all other cells that reference the state getter via a global variable are automatically run with the new state value. This is similar to how interacting with a UI element automatically runs all cells that use the element. The on_change callback. Every UI element takes an optional on_change callback, a function that takes the new value of the element and does anything with it. You can use the setter function in an on_change callback to mutate state.

🌊 Try it! Click the button below and watch what happens.

The counter's current value is 0! This cell runs automatically on button click, even though it doesn't reference either button.
Calling a state's setter in one cell won't ever cause that same cell to re-execute, even if it reads that state getter. This prevents accidental infinite loops and makes some things, like tying elements, easier."

Tied elements

Use state to tie two UI elements to the same value.

To tie elements, you must mo.state, and the tied elements must be created in different cells (since self-loops with state are not allowed).

Example: Task list

No tasks! 🎉

Appendix

The remaining cells are helper data structures and functions. You can look at their code if you’re curious how certain parts of this tutorial were implemented.

Back to top