marimo https://docs.marimo.io marimo: The Reactive Python Notebook[¶](#marimo-the-reactive-python-notebook "Permanent link") ---------------------------------------------------------------------------------------------- marimo is an [open-source](https://github.com/marimo-team/marimo) reactive Python notebook: run a cell or interact with a UI element, and marimo automatically runs dependent cells (or [marks them as stale](https://docs.marimo.io/guides/reactivity/#configuring-how-marimo-runs-cells)), keeping code and outputs consistent and preventing bugs before they happen. Every marimo notebook is stored as pure Python (Git-friendly), [executable as a script](https://docs.marimo.io/guides/scripts/), and [deployable as an app](https://docs.marimo.io/guides/apps/); while stored as Python, marimo notebooks also have [native support for SQL](https://docs.marimo.io/guides/working_with_data/sql/). _Get started instantly with [molab, our free online notebook](https://molab.marimo.io/notebooks). Or get started locally by installing marimo with your favorite package manager:_ install with pipinstall with uvinstall with conda `[](#__codelineno-0-1)pip install marimo && marimo tutorial intro` `[](#__codelineno-1-1)uv add marimo && uv run marimo tutorial intro` `[](#__codelineno-2-1)conda install -c conda-forge marimo && marimo tutorial intro` Developer experience is core to marimo, with an emphasis on reproducibility, maintainability, composability, and shareability. Highlights[¶](#highlights "Permanent link") ------------------------------------------- * 🚀 **batteries-included:** replaces `jupyter`, `streamlit`, `jupytext`, `ipywidgets`, `papermill`, and more * ⚡️ **reactive**: run a cell, and marimo reactively [runs all dependent cells](https://docs.marimo.io/guides/reactivity/) or [marks them as stale](#expensive-notebooks) * 🖐️ **interactive:** [bind sliders, tables, plots, and more](https://docs.marimo.io/guides/interactivity/) to Python — no callbacks required * 🐍 **git-friendly:** stored as `.py` files * 🛢️ **designed for data**: query dataframes, databases, warehouses, and lakehouses [with SQL](https://docs.marimo.io/guides/working_with_data/sql/); filter and search [dataframes](https://docs.marimo.io/guides/working_with_data/dataframes/) * 🤖 **AI-native**: [generate cells with AI](https://docs.marimo.io/guides/generate_with_ai/) tailored for data work * 🔬 **reproducible:** [no hidden state](https://docs.marimo.io/guides/reactivity/), deterministic execution, [built-in package management](https://docs.marimo.io/guides/editor_features/package_management/) * 🏃 **executable:** [execute as a Python script](https://docs.marimo.io/guides/scripts/), parameterized by CLI args * 🛜 **shareable**: [deploy as an interactive web app](https://docs.marimo.io/guides/apps/) or [slides](https://docs.marimo.io/guides/apps/#slides-layout), [run in the browser via WASM](https://docs.marimo.io/guides/wasm/) * 🧩 **reusable:** [import functions and classes](https://docs.marimo.io/guides/reusing_functions/) from one notebook to another * 🧪 **testable:** [run pytest](https://docs.marimo.io/guides/testing/) on notebooks * ⌨️ **a modern editor**: [GitHub Copilot](https://docs.marimo.io/guides/editor_features/ai_completion/#github-copilot), [AI assistants](https://docs.marimo.io/guides/editor_features/ai_completion/), [vim keybindings](https://docs.marimo.io/guides/editor_features/overview/#vim-keybindings), variable explorer, and [more](https://docs.marimo.io/guides/editor_features/) * 🧑‍💻 **use your favorite editor**: run in [VS Code or Cursor](https://marketplace.visualstudio.com/items?itemName=marimo-team.vscode-marimo), or edit in neovim, Zed, [or any other text editor](https://docs.marimo.io/guides/editor_features/watching/) A reactive programming environment[¶](#a-reactive-programming-environment "Permanent link") ------------------------------------------------------------------------------------------- marimo guarantees your notebook code, outputs, and program state are consistent. This [solves many problems](https://docs.marimo.io/faq/#faq-problems) associated with traditional notebooks like Jupyter. **A reactive programming environment.** Run a cell and marimo _reacts_ by automatically running the cells that reference its variables, eliminating the error-prone task of manually re-running cells. Delete a cell and marimo scrubs its variables from program memory, eliminating hidden state. **Compatible with expensive notebooks.** marimo lets you [configure the runtime to be lazy](https://docs.marimo.io/guides/configuration/runtime_configuration/), marking affected cells as stale instead of automatically running them. This gives you guarantees on program state while preventing accidental execution of expensive cells. **Synchronized UI elements.** Interact with [UI elements](https://docs.marimo.io/guides/interactivity/) like [sliders](https://docs.marimo.io/api/inputs/slider/#slider), [dropdowns](https://docs.marimo.io/api/inputs/dropdown/), [dataframe transformers](https://docs.marimo.io/api/inputs/dataframe/), and [chat interfaces](https://docs.marimo.io/api/inputs/chat/), and the cells that use them are automatically re-run with their latest values. **Interactive dataframes.** [Page through, search, filter, and sort](https://docs.marimo.io/guides/working_with_data/dataframes/) millions of rows blazingly fast, no code required. **Generate cells with data-aware AI.** [Generate code with an AI assistant](https://docs.marimo.io/guides/editor_features/ai_completion/) that is highly specialized for working with data, with context about your variables in memory; [zero-shot entire notebooks](https://docs.marimo.io/guides/generate_with_ai/text_to_notebook/). Customize the system prompt, bring your own API keys, or use local models. **Query data with SQL.** Build [SQL](https://docs.marimo.io/guides/working_with_data/sql.html) queries that depend on Python values and execute them against dataframes, databases, lakehouses, CSVs, Google Sheets, or anything else using our built-in SQL engine, which returns the result as a Python dataframe. Your notebooks are still pure Python, even if they use SQL. **Dynamic markdown.** Use markdown parametrized by Python variables to tell dynamic stories that depend on Python data. **Built-in package management.** marimo has built-in support for all major package managers, letting you [install packages on import](https://docs.marimo.io/guides/editor_features/package_management/). marimo can even [serialize package requirements](https://docs.marimo.io/guides/package_management/inlining_dependencies/) in notebook files, and auto install them in isolated venv sandboxes. **Deterministic execution order.** Notebooks are executed in a deterministic order, based on variable references instead of cells' positions on the page. Organize your notebooks to best fit the stories you'd like to tell. **Performant runtime.** marimo runs only those cells that need to be run by statically analyzing your code. **Batteries-included.** marimo comes with [GitHub Copilot](https://docs.marimo.io/guides/editor_features/ai_completion/#github-copilot), AI assistants, Ruff code formatting, HTML export, fast code completion, a [VS Code extension](https://marketplace.visualstudio.com/items?itemName=marimo-team.vscode-marimo), an interactive dataframe viewer, and [many more](https://docs.marimo.io/guides/editor_features/) quality-of-life features. Quickstart[¶](#quickstart "Permanent link") ------------------------------------------- _The [marimo concepts playlist](https://www.youtube.com/watch?v=3N6lInzq5MI&list=PLNJXGo8e1XT9jP7gPbRdm1XwloZVFvLEq) on our [YouTube channel](https://www.youtube.com/@marimo-team) gives an overview of many features._ **Installation.** In a terminal, run `[](#__codelineno-3-1)pip install marimo # or conda install -c conda-forge marimo [](#__codelineno-3-2)marimo tutorial intro` To install with additional dependencies that unlock SQL cells, AI completion, and more, run `[](#__codelineno-4-1)pip install marimo[recommended]` **Create notebooks.** Create or edit notebooks with **Run apps.** Run your notebook as a web app, with Python code hidden and uneditable: `[](#__codelineno-6-1)marimo run your_notebook.py` **Execute as scripts.** Execute a notebook as a script at the command line: **Automatically convert Jupyter notebooks.** Automatically convert Jupyter notebooks to marimo notebooks with the CLI `[](#__codelineno-8-1)marimo convert your_notebook.ipynb > your_notebook.py` or use our [web interface](https://marimo.io/convert). **Tutorials.** List all tutorials: **Share cloud-based notebooks.** Use [molab](https://molab.marimo.io/notebooks), a cloud-based marimo notebook service similar to Google Colab, to create and share notebook links. Questions?[¶](#questions "Permanent link") ------------------------------------------ See our [FAQ](https://docs.marimo.io/faq/). Learn more[¶](#learn-more "Permanent link") ------------------------------------------- marimo is easy to get started with, with lots of room for power users. For example, here's an embedding visualizer made in marimo ([try the notebook live on molab!](https://molab.marimo.io/notebooks/nb_jJiFFtznAy4BxkrrZA1o9b/app?show-code=true)): Check out our [guides](https://docs.marimo.io/guides/), [usage examples](https://docs.marimo.io/examples/), and our [gallery](https://marimo.io/gallery) to learn more.
TutorialInputsPlotsLayout
Contributing[¶](#contributing "Permanent link") ----------------------------------------------- We appreciate all contributions! You don't need to be an expert to help out. Please see [CONTRIBUTING.md](https://github.com/marimo-team/marimo/blob/main/CONTRIBUTING.md) for more details on how to get started. > Questions? Reach out to us [on Discord](https://marimo.io/discord?ref=docs). We're building a community. Come hang out with us! * 🌟 [Star us on GitHub](https://github.com/marimo-team/marimo) * 💬 [Chat with us on Discord](https://marimo.io/discord?ref=docs) * 📧 [Subscribe to our Newsletter](https://marimo.io/newsletter) * ☁️ [Join our Cloud Waitlist](https://marimo.io/cloud) * ✏️ [Start a GitHub Discussion](https://github.com/marimo-team/marimo/discussions) * 💬 [Follow us on Bluesky](https://bsky.app/profile/marimo.io) * 🐦 [Follow us on Twitter](https://twitter.com/marimo_io) * 🎥 [Subscribe on YouTube](https://www.youtube.com/@marimo-team) * 💬 [Follow us on Mastodon](https://mastodon.social/@marimo_io) * 🤖 [Follow us on Reddit](https://www.reddit.com/r/marimo_notebook) * 🕴️ [Follow us on LinkedIn](https://www.linkedin.com/company/marimo-io) **A NumFOCUS affiliated project.** marimo is a core part of the broader Python ecosystem and is a member of the NumFOCUS community, which includes projects such as NumPy, SciPy, and Matplotlib. Inspiration ✨[¶](#inspiration "Permanent link") ----------------------------------------------- marimo is a **reinvention** of the Python notebook as a reproducible, interactive, and shareable Python program, instead of an error-prone JSON scratchpad. We believe that the tools we use shape the way we think — better tools, for better minds. With marimo, we hope to provide the Python community with a better programming environment to do research and communicate it; to experiment with code and share it; to learn computational science and teach it. Our inspiration comes from many places and projects, especially [Pluto.jl](https://github.com/fonsp/Pluto.jl), [ObservableHQ](https://observablehq.com/tutorials), and [Bret Victor's essays](http://worrydream.com/). marimo is part of a greater movement toward reactive dataflow programming. From [IPyflow](https://github.com/ipyflow/ipyflow), [streamlit](https://github.com/streamlit/streamlit), [TensorFlow](https://github.com/tensorflow/tensorflow), [PyTorch](https://github.com/pytorch/pytorch/tree/main), [JAX](https://github.com/google/jax), and [React](https://github.com/facebook/react), the ideas of functional, declarative, and reactive programming are transforming a broad range of tools for the better.
Examples - marimo https://docs.marimo.io/examples/ This page includes dozens of bite-sized how-to examples to help you get started with marimo. Be sure to also read the [quickstart](https://docs.marimo.io/getting_started/) and the [user guide](https://docs.marimo.io/guides/), especially the guide on [how marimo runs cells](https://docs.marimo.io/guides/reactivity/). Get inspired at our gallery! For inspirational examples, including embedding-driven data labelers, Stanford-scientist authored tutorials, and more, check out our [public gallery](https://marimo.io/gallery). Running cells[¶](#running-cells "Permanent link") ------------------------------------------------- * ⚡️ [**Basic execution**](https://docs.marimo.io/examples/running_cells/basics/) * 🐞 [**Getting around multiple definition errors**](https://docs.marimo.io/examples/running_cells/multiple_definitions/) * 🛑 [**Stop cells from running**](https://docs.marimo.io/examples/running_cells/stop/) * 🖱️ [**Run cells on button click**](https://docs.marimo.io/examples/running_cells/run_button/) * 🕓 [**Refresh on a timer**](https://docs.marimo.io/examples/running_cells/refresh/) * ⏳ [**Run async functions**](https://docs.marimo.io/examples/running_cells/async_await/) * 💾 [**Caching computations in memory**](https://docs.marimo.io/examples/running_cells/memory_cache/) * 💾 [**Cache computations to persistent storage**](https://docs.marimo.io/examples/running_cells/persistent_cache/) * 🐞 [**Using the debugger**](https://docs.marimo.io/examples/running_cells/debugging/) * 🐍 [**Run notebooks as scripts**](https://docs.marimo.io/guides/scripts/) Visual Outputs[¶](#visual-outputs "Permanent link") --------------------------------------------------- * 📤 [**Cell outputs**](https://docs.marimo.io/examples/outputs/basic_output/) * ✍️ [**Basic markdown**](https://docs.marimo.io/examples/outputs/basic_markdown/) * 💬 [**Console outputs**](https://docs.marimo.io/examples/outputs/console_outputs/) * 📋 [**Capturing console output**](https://docs.marimo.io/examples/outputs/capture_console_outputs/) * 📈 [**Showing plots**](https://docs.marimo.io/examples/outputs/plots/) * 🎥 [**Showing videos and other media**](https://docs.marimo.io/api/media/) * 🎛️ [**Conditionally showing outputs**](https://docs.marimo.io/examples/outputs/conditional_output/) * 🧩 [**Showing multiple outputs in one cell**](https://docs.marimo.io/examples/outputs/multiple_outputs/) ### Writing markdown[¶](#writing-markdown "Permanent link") * ⚡️ [**Python values in markdown**](https://docs.marimo.io/examples/markdown/dynamic_markdown/) * * * * 🪄 [**Mermaid diagrams**](https://docs.marimo.io/examples/markdown/mermaid/) * * * * 🚨 [**Admonitions**](https://docs.marimo.io/examples/markdown/admonitions/) * * * * 📂 [**Collapsible details**](https://docs.marimo.io/examples/markdown/details/) * * * * 😀 [**Emoji**](https://docs.marimo.io/examples/markdown/emoji/) Working with data[¶](#working-with-data "Permanent link") --------------------------------------------------------- ### Dataframes[¶](#dataframes "Permanent link") marimo is designed for working with dataframes. Here are a few examples; see the [dataframes guide](https://docs.marimo.io/guides/working_with_data/dataframes/) for details. * 🧮 [**Interactive dataframe viewer**](https://docs.marimo.io/examples/outputs/dataframes/) * * * * 🔍 [**Select dataframe rows**](https://docs.marimo.io/api/inputs/table/) * * * * ✏️ [**Editable dataframe**](https://docs.marimo.io/api/inputs/data_editor/) * * * * 🛠️ [**Interactive dataframe transformer**](https://docs.marimo.io/api/inputs/dataframe/) * * * ### SQL[¶](#sql "Permanent link") Here are some basic examples, see the [SQL guide](https://docs.marimo.io/guides/working_with_data/sql/) for more details. * 🦆 [**Query dataframes with DuckDB SQL**](https://docs.marimo.io/guides/working_with_data/sql/#example) * 🛢️ [**SQLite, Postgres, and other engines**](https://docs.marimo.io/guides/working_with_data/sql/#connecting-to-a-custom-database) ### Plots[¶](#plots "Permanent link") See the [plotting guide](https://docs.marimo.io/guides/working_with_data/plotting/) for a full overview. * 📊 [**Selecting data with Altair**](https://docs.marimo.io/api/plotting/#reactive-charts-with-altair) * * * * 📉 [**Selecting data with Plotly**](https://docs.marimo.io/guides/working_with_data/plotting/#plotly) * * * * 🔭 [**Showing matplotlib plots**](https://docs.marimo.io/examples/outputs/plots/) ### Progress bars and status elements[¶](#progress-bars-and-status-elements "Permanent link") * 📶 [**Progress bar**](https://docs.marimo.io/examples/outputs/progress_bar/) * * * * 🌀 [**Loading spinner**](https://docs.marimo.io/examples/outputs/spinner/) * * * ### Layouts[¶](#layouts "Permanent link") * 📐 [**Horizontal and vertical stacking**](https://docs.marimo.io/examples/outputs/stacks/) * * * * 📁 [**Accordion toggle**](https://docs.marimo.io/api/layouts/accordion/) * * * * 🗂️ [**Tabs**](https://docs.marimo.io/api/inputs/tabs/) * * * Input elements[¶](#input-elements "Permanent link") --------------------------------------------------- ### Basic input elements[¶](#basic-input-elements "Permanent link") marimo has a large library of interactive UI elements, which you can use without callbacks — just make sure to assign elements to global variables. See the [API reference](https://docs.marimo.io/api/inputs/) for a full list, and the [interactivity guide](https://docs.marimo.io/guides/interactivity/) for rules governing how UI elements work. * 🎚️ [**Slider**](https://docs.marimo.io/api/inputs/slider/) * * * * 🧾 [**Dropdown**](https://docs.marimo.io/api/inputs/dropdown/) * * * * 👆 [**Multi-select**](https://docs.marimo.io/api/inputs/multiselect/) * * * * 🔘 [**Radio buttons**](https://docs.marimo.io/api/inputs/radio/) * * * * ☑️ [**Checkbox**](https://docs.marimo.io/api/inputs/checkbox/) * * * * 📅 [**Date**](https://docs.marimo.io/api/inputs/dates/) * * * * 📁 [**File**](https://docs.marimo.io/api/inputs/file/) * * * * 🔤 [**Text input**](https://docs.marimo.io/api/inputs/text/) * * * * 📝 [**Text area**](https://docs.marimo.io/api/inputs/text_area/) * * * * 🧑‍💻 [**Code editor**](https://docs.marimo.io/api/inputs/code_editor/) * * * * 🔍 [**Table**](https://docs.marimo.io/api/inputs/table/) * * * * 🎙️ [**Microphone**](https://docs.marimo.io/api/inputs/microphone/) * * * * 💬 [**Chat**](https://docs.marimo.io/api/inputs/chat/) * * * * 🔢 [**Matrix**](https://docs.marimo.io/api/inputs/matrix/) * * * ### Composite input elements[¶](#composite-input-elements "Permanent link") Composite input elements let you create a single UI element from multiple other UI elements. * 🧾 [**Form**](https://docs.marimo.io/api/inputs/form/) * * * * 🎒 [**Array**](https://docs.marimo.io/api/inputs/array/) * * * * 📖 [**Dictionary**](https://docs.marimo.io/api/inputs/dictionary/) * * * Getting Started - marimo https://docs.marimo.io/getting_started/ These tutorials will help you get started with marimo | Guide | Description | | --- | --- | | [Installation](https://docs.marimo.io/getting_started/installation/) | Installing marimo | | [Quickstart](https://docs.marimo.io/getting_started/quickstart/) | Create notebooks, run apps, and more from the marimo command-line | | [Key Concepts](https://docs.marimo.io/getting_started/key_concepts/) | A tour of key features and concepts | User Guide - marimo https://docs.marimo.io/guides/ Guides[¶](#guides "Permanent link") ----------------------------------- These guides cover marimo's core concepts. Learn by doing! Prefer a hands-on learning experience? marimo comes packaged with interactive tutorials that you can launch with `marimo tutorial` at the command line. | Guide | Description | | --- | --- | | [Running cells](https://docs.marimo.io/guides/reactivity/) | Understanding how marimo runs cells | | [Interactive elements](https://docs.marimo.io/guides/interactivity/) | Using interactive UI elements | | [Visualizing outputs](https://docs.marimo.io/guides/outputs/) | Creating markdown, plots, and other visual outputs | | [Migrating from Jupyter](https://docs.marimo.io/guides/coming_from/jupyter/) | Tips for transitioning from Jupyter | | [Expensive notebooks](https://docs.marimo.io/guides/expensive_notebooks/) | Tips for working with expensive notebooks | | [Understanding errors](https://docs.marimo.io/guides/understanding_errors/) | Understanding marimo's constraints on notebook code | | [Lint rules](https://docs.marimo.io/guides/lint_rules/) | Comprehensive linting system and rule reference | | [Working with data](https://docs.marimo.io/guides/working_with_data/) | Using SQL cells, no-code dataframe, and reactive plots | | [Package management](https://docs.marimo.io/guides/package_management/) | Inlining dependencies in notebook files and other package management guides | | [Generate with AI](https://docs.marimo.io/guides/generate_with_ai/) | Generate notebooks with AI | | [Editor features](https://docs.marimo.io/guides/editor_features/) | View variables, dataframe schemas, docstrings, and more | | [Using your own editor](https://docs.marimo.io/guides/editor_features/watching/) | Edit notebooks in your own editor and stream changes back to the browser | | [Apps](https://docs.marimo.io/guides/apps/) | Running notebooks as apps | | [Scripts](https://docs.marimo.io/guides/scripts/) | Running notebooks as scripts | | [Reusing functions and classes](https://docs.marimo.io/guides/reusing_functions/) | Importing functions and classes defined in marimo notebooks | | [Tests](https://docs.marimo.io/guides/testing/) | Running unit tests in notebooks | | [Export to other formats](https://docs.marimo.io/guides/exporting/) | Export notebooks to HTML, PDF, ipynb, scripts, and more | | [Run and share in the cloud with molab](https://docs.marimo.io/guides/molab/) | Share cloud-hosted notebooks for free, preview from GitHub, embed in webpages | | [Publish to the web](https://docs.marimo.io/guides/publishing/) | Publish notebooks to molab, embed in webpages, to/from GitHub, and more | | [Deploy notebook servers or apps](https://docs.marimo.io/guides/deploying/) | Deploy notebook servers (JupyterHub, Kubernetes) or read-only apps | | [WebAssembly notebooks](https://docs.marimo.io/guides/wasm/) | Run notebooks entirely in the browser with WebAssembly | | [Configuration](https://docs.marimo.io/guides/configuration/) | Configure various settings | | [Coming from other tools](https://docs.marimo.io/guides/coming_from/) | Transitioning from Jupyter and other tools | | [Extending marimo](https://docs.marimo.io/guides/integrating_with_marimo/) | Rich displays of objects, custom UI plugins | | [State management](https://docs.marimo.io/guides/state/) | Advanced: mutable reactive state | | [Best practices](https://docs.marimo.io/guides/best_practices/) | Best practices to help you get the most out of marimo | | [Debugging](https://docs.marimo.io/guides/debugging/) | Interactive debugging with pdb, debugpy, and AI assistance | | [Troubleshooting](https://docs.marimo.io/guides/troubleshooting/) | Troubleshooting notebooks | API Reference - marimo https://docs.marimo.io/api/ Use the marimo library in marimo notebooks (`import marimo as mo`) to * connect interactive inputs like sliders, dropdowns, and tables to Python, * express yourself with dynamically created markdown, * layout information with tabs or grids, * output media like images and audio, * and more! | | | | --- | --- | | [markdown](https://docs.marimo.io/api/markdown/) | Write markdown with `mo.md` | | [inputs](https://docs.marimo.io/api/inputs/) | Connect sliders, dropdowns, tables, and more to Python | | [layouts](https://docs.marimo.io/api/layouts/) | Customize outputs with accordions, tabs, stacks, and more | | [plotting](https://docs.marimo.io/api/plotting/) | Output interactive plots | | [media](https://docs.marimo.io/api/media/) | Output media like images, audio, PDFs, and plain text | | [diagrams](https://docs.marimo.io/api/diagrams/) | Flow charts, graphs, statistic cards, and more | | [status](https://docs.marimo.io/api/status/) | Display progress indicators | | [outputs](https://docs.marimo.io/api/outputs/) | Modify cell outputs, redirect console output | | [control\_flow](https://docs.marimo.io/api/control_flow/) | Control how cells execute | | [html](https://docs.marimo.io/api/html/) | Manipulate HTML objects | | [query\_params](https://docs.marimo.io/api/query_params/) | Access and set query parameters with `mo.query_params` | | [cli\_args](https://docs.marimo.io/api/cli_args/) | Access command-line arguments with `mo.cli_args` | | [caching](https://docs.marimo.io/api/caching/) | Cache expensive computations in memory or on disk | | [state](https://docs.marimo.io/api/state/) | Synchronize multiple UI elements with `mo.state` | | [app](https://docs.marimo.io/api/app/) | Embed notebooks in other notebooks | | [cell](https://docs.marimo.io/api/cell/) | Run cells defined in another notebook | | [watch](https://docs.marimo.io/api/watch/) | Reactively respond to file changes on disk | | [miscellaneous](https://docs.marimo.io/api/miscellaneous/) | Miscellaneous utilities | FAQ - marimo https://docs.marimo.io/faq/ Choosing marimo[¶](#choosing-marimo "Permanent link") ----------------------------------------------------- ### How is marimo different from Jupyter?[¶](#how-is-marimo-different-from-jupyter "Permanent link") marimo is a reinvention of the Python notebook as a reproducible, interactive, and shareable Python program that can be executed as scripts or deployed as interactive web apps. **Consistent state.** In marimo, your notebook code, outputs, and program state are guaranteed to be consistent. Run a cell and marimo reacts by automatically running the cells that reference its variables. Delete a cell and marimo scrubs its variables from program memory, eliminating hidden state. **Built-in interactivity.** marimo also comes with [UI elements](https://docs.marimo.io/guides/interactivity/) like sliders, a dataframe transformer, and interactive plots that are automatically synchronized with Python. Interact with an element and the cells that use it are automatically re-run with its latest value. **Pure Python programs.** Unlike Jupyter notebooks, marimo notebooks are stored as pure Python files that can be executed as scripts, deployed as interactive web apps, and versioned easily with Git. ### What problems does marimo solve?[¶](#what-problems-does-marimo-solve "Permanent link") marimo solves problems in reproducibility, maintainability, interactivity, reusability, and shareability of notebooks. **Reproducibility.** In Jupyter notebooks, the code you see doesn't necessarily match the outputs on the page or the program state. If you delete a cell, its variables stay in memory, which other cells may still reference; users can execute cells in arbitrary order. This leads to widespread reproducibility issues. [One study](https://blog.jetbrains.com/datalore/2020/12/17/we-downloaded-10-000-000-jupyter-notebooks-from-github-this-is-what-we-learned/#consistency-of-notebooks) analyzed 10 million Jupyter notebooks and found that 36% of them weren't reproducible. In contrast, marimo guarantees that your code, outputs, and program state are consistent, eliminating hidden state and making your notebook reproducible. marimo achieves this by intelligently analyzing your code and understanding the relationships between cells, and automatically re-running cells as needed. In addition, marimo notebooks can serialize package requirements inline; marimo runs these "sandboxed" notebooks in temporary virtual environments, making them [reproducible down to the packages](https://docs.marimo.io/guides/editor_features/package_management/). **Maintainability.** marimo notebooks are stored as pure Python programs (`.py` files). This lets you version them with Git; in contrast, Jupyter notebooks are stored as JSON and require extra steps to version. **Interactivity.** marimo notebooks come with [UI elements](https://docs.marimo.io/guides/interactivity/) that are automatically synchronized with Python (like sliders, dropdowns); _eg_, scrub a slider and all cells that reference it are automatically re-run with the new value. This is difficult to get working in Jupyter notebooks. **Reusability.** marimo notebooks can be executed as Python scripts from the command-line (since they're stored as `.py` files). In contrast, this requires extra steps to do for Jupyter, such as copying and pasting the code out or using external frameworks. We also let you import symbols (functions, classes) defined in a marimo notebook into other Python programs/notebooks, something you can't easily do with Jupyter. **Shareability.** Every marimo notebook can double as an interactive web app, complete with UI elements, which you can serve using the `marimo run` command. This isn't possible in Jupyter without substantial extra effort. _To learn more about problems with traditional notebooks, see these references [\[1\]](https://austinhenley.com/pubs/Chattopadhyay2020CHI_NotebookPainpoints.pdf) [\[2\]](https://www.youtube.com/watch?v=7jiPeIFXb6U&t=1s)._ ### How is `marimo.ui` different from Jupyter widgets?[¶](#how-is-marimoui-different-from-jupyter-widgets "Permanent link") Unlike Jupyter widgets, marimo's interactive elements are automatically synchronized with the Python kernel: no callbacks, no observers, no manually re-running cells. Using marimo[¶](#using-marimo "Permanent link") ----------------------------------------------- ### Is marimo a notebook or a library?[¶](#is-marimo-a-notebook-or-a-library "Permanent link") marimo is both a notebook and a library. * Create _marimo notebooks_ with the editor that opens in your browser when you run `marimo edit`. * Use the _marimo library_ (`import marimo as mo`) in marimo notebooks. Write markdown with `mo.md(...)`, create stateful interactive elements with `mo.ui` (`mo.ui.slider(...)`), and more. See the docs for an [API reference](https://docs.marimo.io/api/). ### What's the difference between a marimo notebook and a marimo app?[¶](#whats-the-difference-between-a-marimo-notebook-and-a-marimo-app "Permanent link") marimo programs are notebooks, apps, or both, depending on how you use them. There are two ways to interact with a marimo program: 1. open it as a computational _notebook_ with `marimo edit` 2. run it as an interactive _app_ with `marimo run` All marimo programs start as notebooks, since they are created with `marimo edit`. Because marimo notebooks are reactive and have built-in interactive elements, many can easily be made into useful and beautiful apps by simply hiding the notebook code: this is what `marimo run` does. Not every notebook needs to be run as an app — marimo notebooks are useful in and of themselves for rapidly exploring data and doing reproducible science. And not every app is improved by interacting with the notebook. In some settings, such as collaborative research, education, and technical presentations, going back and forth between the notebook view and app view (which you can do from `marimo edit`) can be useful! ### How does marimo know what cells to run?[¶](#how-does-marimo-know-what-cells-to-run "Permanent link") marimo reads each cell once to determine what global names it defines and what global names it reads. When a cell is run, marimo runs all other cells that read any of the global names it defines. A global name can refer to a variable, class, function, or import. In other words, marimo uses _static analysis_ to make a dataflow graph out of your cells. Each cell is a node in the graph across which global variables "flow". Whenever a cell is run, either because you changed its code or interacted with a UI element it reads, all its descendants run in turn. ### Does marimo slow my code down?[¶](#does-marimo-slow-my-code-down "Permanent link") No, marimo doesn't slow your code down. marimo determines the dependencies among cells by reading your code, not running or tracing it, so there's zero runtime overhead. ### How do I prevent automatic execution from running expensive cells?[¶](#how-do-i-prevent-automatic-execution-from-running-expensive-cells "Permanent link") Reactive (automatic) execution ensures your code and outputs are always in sync, improving reproducibility by eliminating hidden state and out-of-order execution; marimo also takes care to run only the minimal set of cells needed to keep your notebook up to date. But when some cells take a long time to run, it's understandable to be concerned that automatic execution will kick off expensive cells before you're ready to run them. _Here are some tips to avoid accidental execution of expensive cells:_ * [Disable expensive cells](https://docs.marimo.io/guides/reactivity/#disabling-cells). When a cell is disabled, it and its descendants are blocked from running. * Wrap UI elements in a [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form"). * Use [`mo.stop`](https://docs.marimo.io/api/control_flow/#marimo.stop " marimo.stop") to conditionally stop execution of a cell and its descendants. * Decorate functions with marimo's [`mo.cache`](https://docs.marimo.io/api/caching/#marimo.cache " marimo.cache") to cache expensive intermediate computations. * Use [`mo.persistent_cache`](https://docs.marimo.io/api/caching/#marimo.persistent_cache " marimo.persistent_cache") to cache variables to disk; on re-run, marimo will read values from disk instead of recalculating them as long as the cell is not stale. * Disable automatic execution in the [runtime configuration](https://docs.marimo.io/guides/configuration/runtime_configuration/). ### How do I disable automatic execution?[¶](#how-do-i-disable-automatic-execution "Permanent link") You can disable automatic execution through the notebook runtime settings; see the [guide on runtime configuration](https://docs.marimo.io/guides/configuration/runtime_configuration/). When automatic execution is disabled, marimo still gives you guarantees on your notebook state and automatically marks cells as stale when appropriate. ### How do I use sliders and other interactive elements?[¶](#how-do-i-use-sliders-and-other-interactive-elements "Permanent link") Interactive UI elements like sliders are available in `marimo.ui`. * Assign the UI element to a global variable (`slider = mo.ui.slider(0, 100)`) * Include it in the last expression of a cell to display it (`slider` or `mo.md(f"Choose a value: {slider}")`) * Read its current value in another cell via its `value` attribute (`slider.value`) _When a UI element bound to a global variable is interacted with, all cells referencing the global variable are run automatically_. If you have many UI elements or don't know the elements you'll create until runtime, use `marimo.ui.array` and `marimo.ui.dictionary` to create UI elements that wrap other UI elements (`sliders = mo.ui.array([slider(1, 100) for _ in range(n_sliders)])`). All this and more is explained in the UI tutorial. Run it with at the command line. ### How do I add a submit button to UI elements?[¶](#how-do-i-add-a-submit-button-to-ui-elements "Permanent link") Use the `form` method to add a submit button to a UI element. For example, `[](#__codelineno-1-1)form = marimo.ui.text_area().form()` When wrapped in a form, the text area's value will only be sent to Python when you click the submit button. Access the last submitted value of the text area with `form.value`. ### How do I write markdown?[¶](#how-do-i-write-markdown "Permanent link") Import `marimo` (as `mo`) in a notebook, and use the `mo.md` function. Learn more in the [outputs guide](https://docs.marimo.io/guides/outputs/#markdown) or by running `marimo tutorial markdown`. ### How do I display plots?[¶](#how-do-i-display-plots "Permanent link") Include plots in the last expression of a cell to display them, just like all other outputs. If you're using matplotlib, you can display the `Figure` object (get the current figure with `plt.gcf()`). For examples, run the plots tutorial: Also see the [plotting API reference](https://docs.marimo.io/api/plotting/). ### How do I prevent matplotlib plots from being cut off?[¶](#how-do-i-prevent-matplotlib-plots-from-being-cut-off "Permanent link") If your legend or axes labels are cut off, try calling `plt.tight_layout()` before outputting your plot: `[](#__codelineno-3-1)import matplotlib.pyplot as plt [](#__codelineno-3-2)[](#__codelineno-3-3)plt.plot([-8, 8]) [](#__codelineno-3-4)plt.ylabel("my variable") [](#__codelineno-3-5)plt.tight_layout() [](#__codelineno-3-6)plt.gca()` ### How do I display interactive matplotlib plots?[¶](#how-do-i-display-interactive-matplotlib-plots "Permanent link") Use [`marimo.mpl.interactive`](https://docs.marimo.io/api/plotting/#marimo.mpl.interactive " marimo.mpl.interactive"). `[](#__codelineno-4-1)fig, ax = plt.subplots() [](#__codelineno-4-2)ax.plot([1, 2]) [](#__codelineno-4-3)mo.mpl.interactive(ax)` ### How do I display objects in rows and columns?[¶](#how-do-i-display-objects-in-rows-and-columns "Permanent link") Use `marimo.hstack` and `marimo.vstack`. See the layout tutorial for details: ### How do I show cell code in the app view?[¶](#how-do-i-show-cell-code-in-the-app-view "Permanent link") Use [`mo.show_code`](https://docs.marimo.io/api/outputs/#marimo.show_code " marimo.show_code"). ### How do I create an output with a dynamic number of UI elements?[¶](#how-do-i-create-an-output-with-a-dynamic-number-of-ui-elements "Permanent link") Use [`mo.ui.array`](https://docs.marimo.io/api/inputs/array/#marimo.ui.array " marimo.ui.array"), [`mo.ui.dictionary`](https://docs.marimo.io/api/inputs/dictionary/#marimo.ui.dictionary " marimo.ui.dictionary"), or [`mo.ui.batch`](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch") to create a UI element that wraps a dynamic number of other UI elements. If you need custom formatting, use [`mo.ui.batch`](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch"), otherwise use [`mo.ui.array`](https://docs.marimo.io/api/inputs/array/#marimo.ui.array " marimo.ui.array") or [`mo.ui.dictionary`](https://docs.marimo.io/api/inputs/dictionary/#marimo.ui.dictionary " marimo.ui.dictionary"). For usage examples, see the [recipes for grouping UI elements together](https://docs.marimo.io/recipes/#grouping-ui-elements-together). ### How do I let users interrupt a progress bar iteration?[¶](#how-do-i-let-users-interrupt-a-progress-bar-iteration "Permanent link") To create an interruptible progress bar, run the progress bar in its own thread, and create a button that on change signals to the thread that it should exit. Example: `[](#__codelineno-6-1)import marimo [](#__codelineno-6-2)[](#__codelineno-6-3)__generated_with = "0.20.1" [](#__codelineno-6-4)app = marimo.App() [](#__codelineno-6-5) [](#__codelineno-6-6)[](#__codelineno-6-7)@app.cell [](#__codelineno-6-8)def _(): [](#__codelineno-6-9) import marimo as mo [](#__codelineno-6-10) import time [](#__codelineno-6-11) from threading import Event [](#__codelineno-6-12) return Event, mo, time [](#__codelineno-6-13) [](#__codelineno-6-14)[](#__codelineno-6-15)@app.cell [](#__codelineno-6-16)def _(Event): [](#__codelineno-6-17) cancelled = Event() [](#__codelineno-6-18) return (cancelled,) [](#__codelineno-6-19) [](#__codelineno-6-20)[](#__codelineno-6-21)@app.cell [](#__codelineno-6-22)def _(cancelled, mo): [](#__codelineno-6-23) cancel = mo.ui.button( [](#__codelineno-6-24) label="Interrupt the progress bar", on_change=lambda _: cancelled.set() [](#__codelineno-6-25) ) [](#__codelineno-6-26) cancel [](#__codelineno-6-27) return [](#__codelineno-6-28) [](#__codelineno-6-29)[](#__codelineno-6-30)@app.cell [](#__codelineno-6-31)def _(cancelled, mo, time): [](#__codelineno-6-32) def progress(total): [](#__codelineno-6-33) with mo.status.progress_bar(total=10) as pbar: [](#__codelineno-6-34) for _ in range(10): [](#__codelineno-6-35) if cancelled.is_set(): [](#__codelineno-6-36) pbar.update( [](#__codelineno-6-37) increment=0, subtitle="The user cancelled the iteration" [](#__codelineno-6-38) ) [](#__codelineno-6-39) break [](#__codelineno-6-40) # Sleep... or anything else that releases GIL [](#__codelineno-6-41) time.sleep(0.5) [](#__codelineno-6-42) pbar.update() [](#__codelineno-6-43) [](#__codelineno-6-44) return (progress,) [](#__codelineno-6-45) [](#__codelineno-6-46)[](#__codelineno-6-47)@app.cell [](#__codelineno-6-48)def _(mo, progress): [](#__codelineno-6-49) mo.Thread(target=progress, args=(10,)).start() [](#__codelineno-6-50) return [](#__codelineno-6-51) [](#__codelineno-6-52)[](#__codelineno-6-53)if __name__ == "__main__": [](#__codelineno-6-54) app.run()` ### How do I restart a notebook?[¶](#how-do-i-restart-a-notebook "Permanent link") To clear all program memory and restart the notebook from scratch, open the notebook menu in the top right and click "Restart kernel". ### How do I reload modules?[¶](#how-do-i-reload-modules "Permanent link") Enable automatic reloading of modules via the runtime settings in your marimo installation's user configuration. (Click the "gear" icon in the top right of a marimo notebook). When enabled, marimo will automatically hot-reload modified modules before executing a cell. ### Why aren't my `on_change`/`on_click` handlers being called?[¶](#why-arent-my-on_changeon_click-handlers-being-called "Permanent link") A UI Element's `on_change` (or for buttons, `on_click`) handlers are only called if the element is bound to a global variable. For example, this won't work `[](#__codelineno-7-1)mo.vstack([mo.ui.button(on_change=lambda _: print("I was called")) for _ in range(10)])` In such cases (when you want to output a dynamic number of UI elements), you need to use [`mo.ui.array`](https://docs.marimo.io/api/inputs/array/#marimo.ui.array " marimo.ui.array"), [`mo.ui.dictionary`](https://docs.marimo.io/api/inputs/dictionary/#marimo.ui.dictionary " marimo.ui.dictionary"), or [`mo.ui.batch`](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch"). See the [recipes for grouping UI elements together](https://docs.marimo.io/recipes/#grouping-ui-elements-together) for example code. ### Why are my `on_change` handlers in an array all referencing the last element?[¶](#why-are-my-on_change-handlers-in-an-array-all-referencing-the-last-element "Permanent link") **Don't do this**: In the below snippet, every `on_change` will print `9`!. `[](#__codelineno-8-1)array = mo.ui.array( [](#__codelineno-8-2) [mo.ui.button(on_change=lambda value: print(i)) for i in range(10) [](#__codelineno-8-3)])` **Instead, do this**: Explicitly bind `i` to the current loop value: `[](#__codelineno-9-1)array = mo.ui.array( [](#__codelineno-9-2) [mo.ui.button(on_change=lambda value, i=i: print(i)) for i in range(10)] [](#__codelineno-9-3)) [](#__codelineno-9-4)array` This is necessary because [in Python, closures are late-binding](https://docs.python-guide.org/writing/gotchas/#late-binding-closures). ### Why aren't my SQL brackets working?[¶](#why-arent-my-sql-brackets-working "Permanent link") Our "SQL" cells are really just Python under the hood to keep notebooks as pure Python scripts. By default, we use `f-strings` for SQL strings, which allows for parameterized SQL like `SELECT * from table where value < {min}`. To escape real `{` / `}` that you don't want parameterized, use double `\{\{...\}\}`: `[](#__codelineno-10-1)SELECT unnest([\{\{'a': 42, 'b': 84\}\}, \{\{'a': 100, 'b': NULL\}\}]);` ### How does marimo treat type annotations?[¶](#how-does-marimo-treat-type-annotations "Permanent link") Type annotations are registered as references of a cell, unless they are explicitly written as strings. This helps ensure correctness of code that depends on type annotations at runtime (_e.g._, Pydantic), while still providing a way to omit annotations from affecting dataflow graph. For example, in `A` is treated as a reference, used in determining the dataflow graph, but in `A` isn't made a reference. For Python 3.12+, marimo additionally implements annotation scoping. ### How do I use dotenv?[¶](#how-do-i-use-dotenv "Permanent link") The package `dotenv`'s `loadenv()` function does not work out-of-the box in marimo. Instead, use `dotenv.load_dotenv(dotenv.find_dotenv(usecwd=True))`. ### What packages can I use?[¶](#what-packages-can-i-use "Permanent link") You can use any Python package. marimo cells run arbitrary Python code. ### How do I use marimo on a remote server?[¶](#how-do-i-use-marimo-on-a-remote-server "Permanent link") > We recorded a video tutorial on how to use marimo on a remote server. Check it out [here](https://youtu.be/pam9Hw8rbaA). Use SSH port-forwarding to run marimo on a remote server and connect to it from a browser on your local machine. Make sure to pass the `--headless` flag when starting marimo on remote; on the remote machine, we also recommend using a port other than marimo's default port, such as 8080: _On the remote machine, run:_ `[](#__codelineno-13-1)marimo edit --headless --port 8080` or, if you want to set a custom host: `[](#__codelineno-14-1)marimo edit --headless --host 0.0.0.0 --port 8080` _On local, run:_ `[](#__codelineno-15-1)ssh -N -L 3718:127.0.0.1:8080 REMOTE_USER@REMOTE_HOST` Then open `localhost:3718` in your browser. ### How do I make marimo accessible on all network interfaces?[¶](#how-do-i-make-marimo-accessible-on-all-network-interfaces "Permanent link") Use `--host 0.0.0.0` with `marimo edit`, `marimo run`, or `marimo tutorial`: `[](#__codelineno-16-1)marimo edit --host 0.0.0.0` ### How do I use marimo behind JupyterHub?[¶](#how-do-i-use-marimo-behind-jupyterhub "Permanent link") JupyterHub can be configured to launch marimo using the [`marimo-jupyter-extension`](https://github.com/marimo-team/marimo-jupyter-extension). ### How do I use marimo with JupyterBook?[¶](#how-do-i-use-marimo-with-jupyterbook "Permanent link") [JupyterBook](https://jupyterbook.org/en/stable/intro.html) makes it easy to create static websites with markdown and Jupyter notebooks. To include a marimo notebook in a JupyterBook, you can either export your notebook to an `ipynb` file, or export to `HTML`: 1. export to ipynb: `marimo export ipynb my_notebook.py -o my_notebook.ipynb --include-outputs` 2. export to HTML: `marimo export html my_notebook.py -o my_notebook.html` ### How do I deploy apps?[¶](#how-do-i-deploy-apps "Permanent link") Use the marimo CLI's `run` command to serve a notebook as an app: If you are running marimo inside a Docker container, you may want to run under a different host and port: `[](#__codelineno-18-1)marimo run notebook.py --host 0.0.0.0 --port 8080` ### Is marimo free?[¶](#is-marimo-free "Permanent link") Yes! Commands - marimo https://docs.marimo.io/cli/ Welcome to marimo! Getting started: * marimo tutorial intro Example usage: * marimo edit create or edit notebooks * marimo edit notebook.py create or edit a notebook called notebook.py * marimo run notebook.py run a notebook as a read-only app * marimo tutorial --help list tutorials **Usage:** `[](#__codelineno-0-1)marimo [OPTIONS] COMMAND [ARGS]...` **Options:** | Name | Type | Description | Default | | --- | --- | --- | --- | | `--version` | boolean | Show the version and exit. | `False` | | `-l`, `--log-level` | choice (`DEBUG` | `INFO` | `WARN` | `ERROR` | `CRITICAL`) | Choose logging level. | `WARN` | | `-q`, `--quiet` | boolean | Suppress standard out. | `False` | | `-y`, `--yes` | boolean | Automatic yes to prompts, running non-interactively. | `False` | | `-d`, `--development-mode` | boolean | Run in development mode; enables debug logs and server autoreload. | `False` | | `--help`, `-h` | boolean | Show this message and exit. | `False` | marimo check[¶](#marimo-check "Permanent link") ----------------------------------------------- Check and format marimo files. **Usage:** `[](#__codelineno-1-1)marimo check [OPTIONS] [FILES]...` **Options:** | Name | Type | Description | Default | | --- | --- | --- | --- | | `--fix` | boolean | Whether to in place update files. | `False` | | `--strict` | boolean | Whether warnings return a non-zero exit code. | `False` | | `-v`, `--verbose` / `-q`, `--quiet` | boolean | Whether to print detailed messages. | `True` | | `--unsafe-fixes` | boolean | Enable fixes that may change code behavior (e.g., removing empty cells). | `False` | | `--ignore-scripts` | boolean | Ignore files that are not recognizable as marimo notebooks. | `False` | | `--format` | choice (`full` | `json`) | Output format for diagnostics. | `full` | | `--select` | text | Comma-separated rule codes/prefixes to enable, replacing config. e.g. --select MB,MR001 | None | | `--ignore` | text | Comma-separated rule codes/prefixes to ignore. e.g. --ignore MF004,MF007 | None | | `--help`, `-h` | boolean | Show this message and exit. | `False` | marimo config[¶](#marimo-config "Permanent link") ------------------------------------------------- Various commands for the marimo config. **Usage:** `[](#__codelineno-2-1)marimo config [OPTIONS] COMMAND [ARGS]...` **Options:** | Name | Type | Description | Default | | --- | --- | --- | --- | | `--help`, `-h` | boolean | Show this message and exit. | `False` | ### marimo config describe[¶](#marimo-config-describe "Permanent link") Describe the marimo config. **Usage:** `[](#__codelineno-3-1)marimo config describe [OPTIONS]` **Options:** | Name | Type | Description | Default | | --- | --- | --- | --- | | `--help`, `-h` | boolean | Show this message and exit. | `False` | ### marimo config show[¶](#marimo-config-show "Permanent link") Show the marimo config. **Usage:** `[](#__codelineno-4-1)marimo config show [OPTIONS]` **Options:** | Name | Type | Description | Default | | --- | --- | --- | --- | | `--help`, `-h` | boolean | Show this message and exit. | `False` | marimo convert[¶](#marimo-convert "Permanent link") --------------------------------------------------- Convert a Jupyter notebook, Markdown file, or Python script to a marimo notebook. Supported input formats: - `.ipynb` (local or GitHub-hosted) - `.md` files with `{python}` code fences - `.py` scripts in py:percent format Behavior: - Jupyter notebooks: outputs are stripped. * Markdown files: only `{python}` fenced code blocks are converted. Example: \- Python scripts: - If already a valid marimo notebook, no conversion is performed. - Otherwise, marimo attempts to convert using py:percent formatting, preserving top-level comments and docstrings. Example usage: `marimo convert your_nb.ipynb -o your_nb.py` or `marimo convert your_nb.md -o your_nb.py` or `marimo convert script.py -o your_nb.py` You can also pass global flags to the main marimo command. For example, use `-q` to suppress output or `-y` to automatically accept all prompts of the command. `marimo -q -y convert script.py -o your_nb.py` After conversion: Note: Since marimo's reactive execution differs from traditional notebooks, you may need to refactor code that mutates variables across cells (e.g., modifying a dataframe in multiple cells), which can lead to unexpected behavior. **Usage:** `[](#__codelineno-6-1)marimo convert [OPTIONS] FILENAME` **Options:** | Name | Type | Description | Default | | --- | --- | --- | --- | | `-o`, `--output` | path | Output file to save the converted notebook to. If not provided, the converted notebook will be printed to stdout. | None | | `--help`, `-h` | boolean | Show this message and exit. | `False` | marimo edit[¶](#marimo-edit "Permanent link") --------------------------------------------- Create or edit notebooks. * marimo edit Start the marimo notebook server * marimo edit notebook.py Create or edit notebook.py **Usage:** `[](#__codelineno-7-1)marimo edit [OPTIONS] [NAME] [ARGS]...` **Options:** | Name | Type | Description | Default | | --- | --- | --- | --- | | `-p`, `--port` | integer | Port to attach to. | None | | `--host` | text | Host to attach to. | `127.0.0.1` | | `--proxy` | text | Address of reverse proxy. | None | | `--headless` | boolean | Don't launch a browser. | `False` | | `--token` / `--no-token` | boolean | Use a token for authentication. This enables session-based authentication. A random token will be generated if --token-password is not set. If --no-token is set, session-based authentication will not be used. | `True` | | `--token-password` | text | Use a specific token for authentication. This enables session-based authentication. A random token will be generated if not set. | None | | `--token-password-file` | text | Path to file containing token password, or '-' for stdin. Mutually exclusive with --token-password. | None | | `--base-url` | text | Base URL for the server. Should start with a /. | \`\` | | `--allow-origins` | text | Allowed origins for CORS. Can be repeated. Use \* for all origins. | None | | `--skip-update-check` | boolean | Don't check if a new version of marimo is available for download. | `False` | | `--sandbox` / `--no-sandbox` | boolean | Run the notebook in an isolated environment, with dependencies tracked via PEP 723 inline metadata. If already declared, dependencies will install automatically. Requires uv. | None | | `--trusted` / `--untrusted` | boolean | Run notebooks hosted remotely on the host machine; if --untrusted, runs marimo in a Docker container. | None | | `--watch` | boolean | Watch the file for changes and reload the code when saved in another editor. | `False` | | `--skew-protection` / `--no-skew-protection` | boolean | Enable skew protection middleware to prevent version mismatch issues. | `True` | | `--timeout` | float | Enable a global timeout to shut down the server after specified number of minutes of no connection | None | | `--session-ttl` | integer | Seconds to wait before closing a session on websocket disconnect. If None is provided, sessions are not automatically closed. | None | | `--help`, `-h` | boolean | Show this message and exit. | `False` | marimo env[¶](#marimo-env "Permanent link") ------------------------------------------- Print out environment information for debugging purposes. **Usage:** **Options:** | Name | Type | Description | Default | | --- | --- | --- | --- | | `--help`, `-h` | boolean | Show this message and exit. | `False` | marimo export[¶](#marimo-export "Permanent link") ------------------------------------------------- Export a notebook to various formats. **Usage:** `[](#__codelineno-9-1)marimo export [OPTIONS] COMMAND [ARGS]...` **Options:** | Name | Type | Description | Default | | --- | --- | --- | --- | | `--help`, `-h` | boolean | Show this message and exit. | `False` | ### marimo export html[¶](#marimo-export-html "Permanent link") Run a notebook and export it as an HTML file. Example: `marimo export html notebook.py -o notebook.html` Optionally pass CLI args to the notebook: `marimo export html notebook.py -o notebook.html -- -arg1 foo -arg2 bar` **Usage:** `[](#__codelineno-10-1)marimo export html [OPTIONS] NAME [ARGS]...` **Options:** | Name | Type | Description | Default | | --- | --- | --- | --- | | `--include-code` / `--no-include-code` | boolean | Include notebook code in the exported HTML file. | `True` | | `--watch` / `--no-watch` | boolean | Watch notebook for changes and regenerate the output on modification. If watchdog is installed, it will be used to watch the file. Otherwise, file watcher will poll the file every 1s. | `False` | | `-o`, `--output` | path | Output file to save the HTML to. If not provided, the HTML will be printed to stdout. | None | | `--sandbox` / `--no-sandbox` | boolean | Run the command in an isolated virtual environment using `uv run --isolated`. Requires `uv`. | None | | `-f`, `--force` | boolean | Force overwrite of the output file if it already exists. | `False` | | `--help`, `-h` | boolean | Show this message and exit. | `False` | ### marimo export html-wasm[¶](#marimo-export-html-wasm "Permanent link") Export a notebook as a WASM-powered standalone HTML file. Example: `marimo export html-wasm notebook.py -o notebook.wasm.html` The exported HTML file will run the notebook using WebAssembly, making it completely self-contained and executable in the browser. This lets you share interactive notebooks on the web without setting up infrastructure to run Python code. The exported notebook runs using Pyodide, which supports most but not all Python packages. To learn more, see the Pyodide documentation. In order for this file to be able to run, it must be served over HTTP, and cannot be opened directly from the file system (e.g. file://). **Usage:** `[](#__codelineno-11-1)marimo export html-wasm [OPTIONS] NAME` **Options:** | Name | Type | Description | Default | | --- | --- | --- | --- | | `-o`, `--output` | path | Output directory to save the HTML to. | \_required | | `--mode` | choice (`edit` | `run`) | Whether the notebook code should be editable or readonly. | `run` | | `--watch` / `--no-watch` | boolean | Whether to watch the original file and export upon change | `False` | | `--show-code` / `--no-show-code` | boolean | Whether to show code by default in the exported HTML file; only relevant for run mode. | `False` | | `--include-cloudflare` / `--no-include-cloudflare` | boolean | Whether to include Cloudflare Worker configuration files (index.js and wrangler.jsonc) for easy deployment. | `False` | | `--sandbox` / `--no-sandbox` | boolean | Run the command in an isolated virtual environment using `uv run --isolated`. Requires `uv`. | None | | `-f`, `--force` | boolean | Force overwrite of the output file if it already exists. | `False` | | `--help`, `-h` | boolean | Show this message and exit. | `False` | ### marimo export ipynb[¶](#marimo-export-ipynb "Permanent link") Export a marimo notebook as a Jupyter notebook in topological order. Example: `marimo export ipynb notebook.py -o notebook.ipynb` Watch for changes and regenerate the script on modification: `marimo export ipynb notebook.py -o notebook.ipynb --watch` Optionally pass CLI args to the notebook: `marimo export ipynb notebook.py -o notebook.ipynb --include-outputs -- -arg1 foo -arg2 bar` Requires nbformat to be installed. **Usage:** `[](#__codelineno-12-1)marimo export ipynb [OPTIONS] NAME [ARGS]...` **Options:** | Name | Type | Description | Default | | --- | --- | --- | --- | | `--sort` | choice (`top-down` | `topological`) | Sort cells top-down or in topological order. | `topological` | | `--watch` / `--no-watch` | boolean | Watch notebook for changes and regenerate the output on modification. If watchdog is installed, it will be used to watch the file. Otherwise, file watcher will poll the file every 1s. | `False` | | `-o`, `--output` | path | Output file to save the ipynb file to. If not provided, the ipynb contents will be printed to stdout. | None | | `--include-outputs` / `--no-include-outputs` | boolean | Run the notebook and include outputs in the exported ipynb file. | `False` | | `--sandbox` / `--no-sandbox` | boolean | Run the command in an isolated virtual environment using `uv run --isolated`. Requires `uv`. | None | | `-f`, `--force` | boolean | Force overwrite of the output file if it already exists. | `False` | | `--help`, `-h` | boolean | Show this message and exit. | `False` | ### marimo export md[¶](#marimo-export-md "Permanent link") Export a marimo notebook as a code fenced Markdown file. Example: `marimo export md notebook.py -o notebook.md` Watch for changes and regenerate the script on modification: `marimo export md notebook.py -o notebook.md --watch` **Usage:** `[](#__codelineno-13-1)marimo export md [OPTIONS] NAME` **Options:** | Name | Type | Description | Default | | --- | --- | --- | --- | | `--watch` / `--no-watch` | boolean | Watch notebook for changes and regenerate the output on modification. If watchdog is installed, it will be used to watch the file. Otherwise, file watcher will poll the file every 1s. | `False` | | `-o`, `--output` | path | Output file to save the markdown to. If not provided, markdown will be printed to stdout. | None | | `--sandbox` / `--no-sandbox` | boolean | Run the command in an isolated virtual environment using `uv run --isolated`. Requires `uv`. | None | | `-f`, `--force` | boolean | Force overwrite of the output file if it already exists. | `False` | | `--help`, `-h` | boolean | Show this message and exit. | `False` | ### marimo export pdf[¶](#marimo-export-pdf "Permanent link") Export a marimo notebook as a PDF file. Example: `marimo export pdf notebook.py -o notebook.pdf` Optionally pass CLI args to the notebook: `marimo export pdf notebook.py -o notebook.pdf -- -arg1 foo -arg2 bar` Export PDFs in a specific format such as slides: `marimo export pdf notebook.py -o notebook.pdf --as=slides` Requires nbformat and nbconvert to be installed. **Usage:** `[](#__codelineno-14-1)marimo export pdf [OPTIONS] NAME [ARGS]...` **Options:** | Name | Type | Description | Default | | --- | --- | --- | --- | | `--include-outputs` / `--no-include-outputs` | boolean | Run the notebook and include outputs in the exported PDF file. | `True` | | `--include-inputs` / `--no-include-inputs` | boolean | Include code cell inputs in the exported PDF file. | `True` | | `--webpdf` / `--no-webpdf` | boolean | Use nbconvert's WebPDF exporter (Chromium). If disabled, marimo will try standard PDF export (pandoc + TeX) first and fall back to WebPDF. | `True` | | `--rasterize-outputs` / `--no-rasterize-outputs` | boolean | Rasterize marimo widget HTML and Vega outputs to PNG fallbacks before PDF conversion (enabled by default). | `True` | | `--raster-scale` | float range (between `1.0` and `4.0`) | Scale factor for rasterized output screenshots. | `4.0` | | `--raster-server` | choice (`static` | `live`) | Server mode used for raster capture. Use 'static' (default) for faster captures, or 'live' if outputs require a live Python connection. For --as=slides, 'live' is recommended. | `static` | | `--as` | choice (`document` | `slides`) | PDF export preset. Use `slides` for reveal.js slide-style output. If omitted, marimo exports as a standard document PDF. | None | | `--watch` / `--no-watch` | boolean | Watch notebook for changes and regenerate the output on modification. If watchdog is installed, it will be used to watch the file. Otherwise, file watcher will poll the file every 1s. | `False` | | `-o`, `--output` | path | Output PDF file to save to. | \_required | | `--sandbox` / `--no-sandbox` | boolean | Run the command in an isolated virtual environment using `uv run --isolated`. Requires `uv`. | None | | `-f`, `--force` | boolean | Force overwrite of the output file if it already exists. | `False` | | `--help`, `-h` | boolean | Show this message and exit. | `False` | ### marimo export script[¶](#marimo-export-script "Permanent link") Export a marimo notebook as a flat script, in topological order. Example: `marimo export script notebook.py -o notebook.script.py` Watch for changes and regenerate the script on modification: `marimo export script notebook.py -o notebook.script.py --watch` **Usage:** `[](#__codelineno-15-1)marimo export script [OPTIONS] NAME` **Options:** | Name | Type | Description | Default | | --- | --- | --- | --- | | `--watch` / `--no-watch` | boolean | Watch notebook for changes and regenerate the output on modification. If watchdog is installed, it will be used to watch the file. Otherwise, file watcher will poll the file every 1s. | `False` | | `-o`, `--output` | path | Output file to save the script to. If not provided, the script will be printed to stdout. | None | | `--sandbox` / `--no-sandbox` | boolean | Run the command in an isolated virtual environment using `uv run --isolated`. Requires `uv`. | None | | `-f`, `--force` | boolean | Force overwrite of the output file if it already exists. | `False` | | `--help`, `-h` | boolean | Show this message and exit. | `False` | ### marimo export session[¶](#marimo-export-session "Permanent link") Execute a notebook or directory of notebooks and export session snapshots. **Usage:** `[](#__codelineno-16-1)marimo export session [OPTIONS] NAME [ARGS]...` **Options:** | Name | Type | Description | Default | | --- | --- | --- | --- | | `--sandbox` / `--no-sandbox` | boolean | Run the command in an isolated virtual environment using `uv run --isolated`. Requires `uv`. | None | | `--force-overwrite` / `--no-force-overwrite` | boolean | Overwrite all existing session snapshots, even if they are already up-to-date. | `False` | | `--continue-on-error` / `--no-continue-on-error` | boolean | Continue processing other notebooks if one notebook fails. | `True` | | `--help`, `-h` | boolean | Show this message and exit. | `False` | ### marimo export thumbnail[¶](#marimo-export-thumbnail "Permanent link") Generate OpenGraph thumbnails for notebooks. **Usage:** `[](#__codelineno-17-1)marimo export thumbnail [OPTIONS] NAME [ARGS]...` **Options:** | Name | Type | Description | Default | | --- | --- | --- | --- | | `--width` | integer | Viewport width for the screenshot. | `1200` | | `--height` | integer | Viewport height for the screenshot. | `630` | | `--scale` | integer range (between `1` and `4`) | Device scale factor for screenshots. Output resolution will be `width*scale` x `height*scale`. | `2` | | `--timeout-ms` | integer | Additional time to wait after page load before screenshot. | `1500` | | `--output` | path | Output filename. If omitted, writes to `/__marimo__/assets//opengraph.png`. | None | | `--overwrite` / `--no-overwrite` | boolean | Overwrite existing thumbnails. | `False` | | `--include-code` / `--no-include-code` | boolean | Whether to include code in the rendered HTML before screenshot. | `False` | | `--execute` / `--no-execute` | boolean | Execute notebooks and include their outputs in thumbnails. In --no-execute mode (default), thumbnails are generated from notebook structure without running code (and will not include outputs). | `False` | | `--sandbox` / `--no-sandbox` | boolean | Render notebooks in an isolated environment, with dependencies tracked via PEP 723 inline metadata. If already declared, dependencies will install automatically. Requires uv. Only applies when --execute is used. | None | | `--continue-on-error` / `--fail-fast` | boolean | Continue processing other notebooks if one notebook fails. | `True` | | `--help`, `-h` | boolean | Show this message and exit. | `False` | marimo new[¶](#marimo-new "Permanent link") ------------------------------------------- Create an empty notebook, or generate from a prompt with AI * marimo new Create an empty notebook * marimo new "Plot an interactive 3D surface with matplotlib." Generate a notebook from a prompt. * marimo new prompt.txt Generate a notebook from a file containing a prompt. Visit [https://marimo.app/ai](https://marimo.app/ai) for more prompt examples. **Usage:** `[](#__codelineno-18-1)marimo new [OPTIONS] [PROMPT]` **Options:** | Name | Type | Description | Default | | --- | --- | --- | --- | | `-p`, `--port` | integer | Port to attach to. | None | | `--host` | text | Host to attach to. | `127.0.0.1` | | `--proxy` | text | Address of reverse proxy. | None | | `--headless` | boolean | Don't launch a browser. | `False` | | `--token` / `--no-token` | boolean | Use a token for authentication. This enables session-based authentication. A random token will be generated if --token-password is not set. If --no-token is set, session-based authentication will not be used. | `True` | | `--token-password` | text | Use a specific token for authentication. This enables session-based authentication. A random token will be generated if not set. | None | | `--token-password-file` | text | Path to file containing token password, or '-' for stdin. Mutually exclusive with --token-password. | None | | `--base-url` | text | Base URL for the server. Should start with a /. | \`\` | | `--sandbox` / `--no-sandbox` | boolean | Run the notebook in an isolated environment, with dependencies tracked via PEP 723 inline metadata. If already declared, dependencies will install automatically. Requires uv. | None | | `--skew-protection` / `--no-skew-protection` | boolean | Enable skew protection middleware to prevent version mismatch issues. | `True` | | `--timeout` | float | Enable a global timeout to shut down the server after specified number of minutes of no connection | None | | `--help`, `-h` | boolean | Show this message and exit. | `False` | marimo pair[¶](#marimo-pair "Permanent link") --------------------------------------------- Commands for pair programming with AI. **Usage:** `[](#__codelineno-19-1)marimo pair [OPTIONS] COMMAND [ARGS]...` **Options:** | Name | Type | Description | Default | | --- | --- | --- | --- | | `--help`, `-h` | boolean | Show this message and exit. | `False` | ### marimo pair prompt[¶](#marimo-pair-prompt "Permanent link") Generate a prompt for pair programming on a running marimo notebook. **Usage:** `[](#__codelineno-20-1)marimo pair prompt [OPTIONS]` **Options:** | Name | Type | Description | Default | | --- | --- | --- | --- | | `--url` | text | URL of the running marimo kernel. | \_required | | `--claude` | boolean | Validate that the marimo-pair Claude Code skill is installed. | `False` | | `--codex` | boolean | Validate that the marimo-pair Codex skill is installed. | `False` | | `--opencode` | boolean | Validate that the marimo-pair opencode skill is installed. | `False` | | `--with-token` | boolean | Prompt for an auth token and store it in a temp file. | `False` | | `--help`, `-h` | boolean | Show this message and exit. | `False` | marimo recover[¶](#marimo-recover "Permanent link") --------------------------------------------------- Recover a marimo notebook from JSON. **Usage:** `[](#__codelineno-21-1)marimo recover [OPTIONS] NAME` **Options:** | Name | Type | Description | Default | | --- | --- | --- | --- | | `--help`, `-h` | boolean | Show this message and exit. | `False` | marimo run[¶](#marimo-run "Permanent link") ------------------------------------------- Run a notebook as an app in read-only mode. If NAME is a url, the notebook will be downloaded to a temporary file. Example: `marimo run notebook.py marimo run folder another_folder marimo run app.py -- --arg value` **Usage:** `[](#__codelineno-22-1)marimo run [OPTIONS] NAME [ARGS]...` **Options:** | Name | Type | Description | Default | | --- | --- | --- | --- | | `-p`, `--port` | integer | Port to attach to. | None | | `--host` | text | Host to attach to. | `127.0.0.1` | | `--proxy` | text | Address of reverse proxy. | None | | `--headless` | boolean | Don't launch a browser. | `False` | | `--token` / `--no-token` | boolean | Use a token for authentication. This enables session-based authentication. A random token will be generated if --token-password is not set. If --no-token is set, session-based authentication will not be used. | `False` | | `--token-password` | text | Use a specific token for authentication. This enables session-based authentication. A random token will be generated if not set. | None | | `--token-password-file` | text | Path to file containing token password, or '-' for stdin. Mutually exclusive with --token-password. | None | | `--include-code` | boolean | Include notebook code in the app. | `False` | | `--session-ttl` | integer | Seconds to wait before closing a session on websocket disconnect. | `120` | | `--watch` | boolean | Watch the file for changes and reload the app. If watchdog is installed, it will be used to watch the file. Otherwise, file watcher will poll the file every 1s. | `False` | | `--skew-protection` / `--no-skew-protection` | boolean | Enable skew protection middleware to prevent version mismatch issues. | `True` | | `--base-url` | text | Base URL for the server. Should start with a /. | \`\` | | `--allow-origins` | text | Allowed origins for CORS. Can be repeated. | None | | `--redirect-console-to-browser` | boolean | Redirect console logs to the browser console. | `False` | | `--sandbox` / `--no-sandbox` | boolean | Run the notebook in an isolated environment, with dependencies tracked via PEP 723 inline metadata. If already declared, dependencies will install automatically. Requires uv. | None | | `--check` / `--no-check` | boolean | Disable a static check of the notebook before running. | `True` | | `--trusted` / `--untrusted` | boolean | Run notebooks hosted remotely on the host machine; if --untrusted, runs marimo in a Docker container. | None | | `--show-tracebacks` / `--no-show-tracebacks` | boolean | Show detailed error tracebacks in a modal when exceptions occur. | None | | `--help`, `-h` | boolean | Show this message and exit. | `False` | marimo shell-completion[¶](#marimo-shell-completion "Permanent link") --------------------------------------------------------------------- Install shell completions for marimo. Supports bash, zsh, and fish. **Usage:** `[](#__codelineno-23-1)marimo shell-completion [OPTIONS]` **Options:** | Name | Type | Description | Default | | --- | --- | --- | --- | | `--help`, `-h` | boolean | Show this message and exit. | `False` | marimo tutorial[¶](#marimo-tutorial "Permanent link") ----------------------------------------------------- Open a tutorial. marimo is a powerful library for making reactive notebooks and apps. To get the most out of marimo, get started with a few tutorials, starting with the intro: Recommended sequence: `- intro - dataflow - ui - markdown - plots - sql - layout - fileformat - markdown-format - for-jupyter-users` **Usage:** `[](#__codelineno-24-1)marimo tutorial [OPTIONS] {intro|dataflow|ui|markdown|plots|sql|layout|filefor [](#__codelineno-24-2) mat|markdown-format|for-jupyter-users}` **Options:** | Name | Type | Description | Default | | --- | --- | --- | --- | | `-p`, `--port` | integer | Port to attach to. | None | | `--host` | text | Host to attach to. | `127.0.0.1` | | `--proxy` | text | Address of reverse proxy. | None | | `--headless` | boolean | Don't launch a browser. | `False` | | `--token` / `--no-token` | boolean | Use a token for authentication. This enables session-based authentication. A random token will be generated if --token-password is not set. If --no-token is set, session-based authentication will not be used. | `True` | | `--token-password` | text | Use a specific token for authentication. This enables session-based authentication. A random token will be generated if not set. | None | | `--token-password-file` | text | Path to file containing token password, or '-' for stdin. Mutually exclusive with --token-password. | None | | `--skew-protection` / `--no-skew-protection` | boolean | Enable skew protection middleware to prevent version mismatch issues. | `True` | | `--help`, `-h` | boolean | Show this message and exit. | `False` | Community - marimo https://docs.marimo.io/community/ We're building a community. Come hang out with us! * 🌟 [Star us on GitHub](https://github.com/marimo-team/marimo) * 💬 [Chat with us on Discord](https://marimo.io/discord?ref=readme) * 📧 [Subscribe to our Newsletter](https://marimo.io/newsletter) * ☁️ [Join our Cloud Waitlist](https://marimo.io/cloud) * ✏️ [Start a GitHub Discussion](https://github.com/marimo-team/marimo/discussions) * 🦋 [Follow us on Bluesky](https://bsky.app/profile/marimo.io) * 🐦 [Follow us on Twitter](https://twitter.com/marimo_io) * 🎥 [Subscribe on YouTube](https://www.youtube.com/@marimo-team) * 🕴️ [Follow us on LinkedIn](https://www.linkedin.com/company/marimo-io) Shields[¶](#shields "Permanent link") ------------------------------------- You can use our shield for opening a marimo application: * * * **Markdown** `[](#__codelineno-0-1)[![marimo](https://marimo.io/shield.svg)](https://marimo.app/l/c7h6pz)` **HTML** `[](#__codelineno-1-1) [](#__codelineno-1-2) [](#__codelineno-1-3)` Integrations - marimo https://docs.marimo.io/integrations/ It is easy to integrate your preferred data sources or data warehouses with marimo. Since marimo is strictly Python, you can utilize any Python library to access your data. In this section, we provide some examples of how to integrate with popular data sources. | Integration | Description | | --- | --- | | [MotherDuck](https://docs.marimo.io/integrations/motherduck/) | Integrating with MotherDuck | | [Google Cloud Storage](https://docs.marimo.io/integrations/google_cloud_storage/) | Integrating with Google Cloud Storage | | [Google Cloud BigQuery](https://docs.marimo.io/integrations/google_cloud_bigquery/) | Integrating with Google Cloud BigQuery | | [Google Sheets](https://docs.marimo.io/integrations/google_sheets/) | Integrating with Google Sheets | Security - marimo https://docs.marimo.io/security/ marimo takes security seriously. This document describes marimo's security model, our approach to vulnerability disclosure, and how to report security issues. Security Model[¶](#security-model "Permanent link") --------------------------------------------------- When you open a notebook, marimo assumes you might not trust its contents until you explicitly choose to run it. Once you've run code, marimo treats the outputs as trusted since they came from your execution. Like other notebooks, marimo allows arbitrary code execution when you run cells. This means that if you run code from untrusted sources, you could inadvertently execute malicious code. Therefore, it's important to only run notebooks from sources you trust or to review the code before executing it. However, marimo implements several security measures to minimize risks when opening and editing notebooks. Our blanket policy is that no user code is executed without explicit user action (either as javascript or python). ### Content sanitization[¶](#content-sanitization "Permanent link") marimo sanitizes HTML and JavaScript in specific contexts to prevent malicious code from executing when you open untrusted notebooks. All user content shown before execution is sanitized to remove all scripts (including markdown and custom HTML outputs). After initial execution, outputs are trusted since they were generated by your code. Being a responsible notebook user means running code from sources you trust, and/or reviewing code before executing it. ### Static loading[¶](#static-loading "Permanent link") Although marimo notebook are just python files, opening a notebook through `marimo edit` does not execute it as a module. marimo notebooks are statically loaded, meaning they are parsed but not executed as Python modules when opened. This prevents arbitrary code execution at load time. Code only runs when you explicitly execute cells. ### Run modes and trust[¶](#run-modes-and-trust "Permanent link") marimo behaves differently depending on how you run it: **Edit mode** (`marimo edit`): * Content is sanitized until you run your first cell or `auto_instantiate` is enabled (by default it is `disabled`) * After you run code, subsequent outputs are trusted (you created them) * Token authentication enabled by default for remote access **Run mode** (`marimo run`): * Notebooks run as web applications * Content is treated as a trusted website (no sanitization) * Token authentication can be configured via CLI flags or custom middleware * With `marimo run --watch`, newly created notebooks in the watched folder can appear in gallery mode without restarting the server This distinction reflects the different threat models: editing is exploratory and may involve untrusted notebooks; deployed apps are intentional publications. ### Authentication[¶](#authentication "Permanent link") marimo provides token-based authentication: * Enabled by default when running `marimo edit` * Configurable in run mode via `--token` and `--token-password` flags * Extensible through ASGI middleware for custom authentication schemes See the [Authentication guide](https://docs.marimo.io/guides/deploying/authentication/) for more details. ### Added security measures on [https://molab.marimo.io](https://molab.marimo.io/)[¶](#added-security-measures-on-httpsmolabmarimoio "Permanent link") [molab](https://molab.marimo.io/) takes a few other addition precautions. * Auto-running cells is disabled on notebook load (you can disable this during your session) * Custom head tags are disabled These restrictions prevent code execution without explicit user consent. Security Advisories[¶](#security-advisories "Permanent link") ------------------------------------------------------------- marimo publishes security advisories for vulnerabilities that affect production deployments, particularly long-running applications. We follow responsible disclosure practices and work with security researchers to address issues. ### CVE Policy[¶](#cve-policy "Permanent link") We issue CVEs and security advisories when: * A vulnerability could affect long-running app deployments * End-users are directly impacted * The issue has security implications beyond normal bug fixes For general safety improvements and hardening work, we document changes in our [release notes](https://github.com/marimo-team/marimo/releases) without issuing formal advisories. molab Security[¶](#molab-security "Permanent link") --------------------------------------------------- [molab](https://docs.marimo.io/guides/molab/) is marimo's hosted notebook platform. For security issues affecting molab: * We handle disclosure on a case-by-case basis * General security improvements are disclosed publicly when applicable, and will be documented on this page. * User-specific issues are handled privately through direct notification * Reports can be submitted through the same channels: [GitHub advisories](https://github.com/marimo-team/marimo/security/advisories/new) or security \[at\] marimo \[dot\] io Reporting Vulnerabilities[¶](#reporting-vulnerabilities "Permanent link") ------------------------------------------------------------------------- We appreciate the security research community's efforts to improve marimo's security. If you discover a vulnerability: **How to report:** 1. [Draft a security advisory on GitHub](https://github.com/marimo-team/marimo/security/advisories/new), or 2. Email the marimo team at security \[at\] marimo \[dot\] io **What to expect:** * We review all reports and respond to actionable issues * Advisories affecting end-users are escalated to CVEs when appropriate * We provide attribution for all reports (unless you prefer to remain anonymous) * We have a small allocation for bug bounties; please inquire if interested. **Recognition:** We're grateful to [the security researchers](https://github.com/marimo-team/marimo/blob/main/SECURITY.md) who have responsibly disclosed vulnerabilities. Your contributions help keep marimo safe for the entire community. We encourage responsible disclosure and recognize all security researchers who help improve marimo. Staying Up to Date[¶](#staying-up-to-date "Permanent link") ----------------------------------------------------------- marimo ships new releases approximately once per week, and we provide immediate updates for major security disclosures. To ensure you have the latest security fixes, we recommend using `uv` to keep marimo up to date: `[](#__codelineno-0-1)# Install or update to the latest version [](#__codelineno-0-2)uv pip install --upgrade marimo` Using `uv` ensures you benefit from the latest security improvements and patches as soon as they're available. Questions?[¶](#questions "Permanent link") ------------------------------------------ For security questions or concerns, please reach out to security \[at\] marimo \[dot\] io. For general questions about marimo, see our [FAQ](https://docs.marimo.io/faq/) or join us on [Discord](https://marimo.io/discord). ### Previous Advisories[¶](#previous-advisories "Permanent link") Click to expand previous security advisories * **[\[GHSA-xjv7-6w92-42r7\]](https://github.com/marimo-team/marimo/security/advisories/GHSA-xjv7-6w92-42r7)**: Unauthenticated proxy vulnerability in matplotlib endpoint. The `/mpl/[port]/[route]` endpoint allowed external attackers to reach internal services. Affected versions 0.9.20 through 0.16.3. Fixed in 0.16.4. * **\[molab-0\]**: iframe sandbox escape via markdown render. In molab, an attacker could exploit a vulnerability in the iframe sandboxing to escape the iframe and execute code in the parent context. Fixed in molab deployment on 2025-10-19. Installation - marimo https://docs.marimo.io/getting_started/installation/ Before installing marimo, we recommend creating and activating a Python [virtual environment](https://docs.python.org/3/tutorial/venv.html#creating-virtual-environments). Setting up a virtual environment Python uses virtual environments to minimize conflicts among packages. Here's a quickstart for `pip` users. If you use `conda`, please use a [`conda` environment](https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html#creating-an-environment-with-commands) instead. Run the following in the terminal: * create an environment with `python -m venv marimo-env` * activate the environment: * macOS/Unix: `source marimo-env/bin/activate` * Windows: `marimo-env\Scripts\activate` _Make sure the environment is activated before installing marimo and when using marimo._ Install other packages you may need, such as numpy, pandas, matplotlib, and altair, in this environment. When you're done, deactivate the environment with `deactivate` in the terminal. Learn more from the [official Python tutorial](https://docs.python.org/3/tutorial/venv.html#creating-virtual-environments). Using uv? [uv](https://docs.astral.sh/uv/) is a next-generation Python package installer and manager that is 10-100x faster than pip, and also makes it easy to install Python and manage projects. Create a [uv project](https://docs.astral.sh/uv/guides/projects/) with `uv init`; this creates and manages a virtual environment for you behind-the-scenes. For detailed information on using marimo with `uv`, see our [uv guide](https://docs.marimo.io/guides/package_management/using_uv/). Prefer VS Code/Cursor? [Try our extension](https://marketplace.visualstudio.com/items?itemName=marimo-team.vscode-marimo), which works in VS Code, Cursor, and other VS Code forks. Install with minimal dependencies[¶](#install-with-minimal-dependencies "Permanent link") ----------------------------------------------------------------------------------------- To install marimo, run the following in a terminal: install with pipinstall with uvinstall with conda To check if the install worked, run To check if the install worked, run `[](#__codelineno-3-1)uv run marimo tutorial intro` `[](#__codelineno-4-1)conda install -c conda-forge marimo` To check if the install worked, run A tutorial notebook should open in your browser. Install with recommended dependencies[¶](#install-with-recommended-dependencies "Permanent link") ------------------------------------------------------------------------------------------------- marimo is lightweight, with few dependencies, to maximize compatibility with your own environments. To unlock additional features in the marimo editor, including SQL cells, AI completion, server-side plotting of dataframe columns, and more, we suggest installing `marimo[recommended]`: install with pipinstall with uvinstall with conda `[](#__codelineno-6-1)pip install "marimo[recommended]"` `[](#__codelineno-7-1)uv add "marimo[recommended]"` `[](#__codelineno-8-1)conda install -c conda-forge marimo "duckdb>=1.0.0" "altair>=5.4.0" pyarrow "polars>=1.9.0" "sqlglot[c]>=23.4" "openai>=1.55.3" "ruff" "nbformat>=5.7.0" "vegafusion>=2.0.0" "vl-convert-python>=1.0.0"` Installing marimo in this way installs the following additional dependencies and unlocks the following features: | Dependency | Feature | | --- | --- | | duckdb>=1.0.0 | SQL cells | | altair>=5.4.0 | Plotting in datasource viewer | | polars\[pyarrow\]>=1.9.0 | SQL output back in Python | | sqlglot\[c\]>=23.4 | SQL cells parsing | | openai>=1.55.3 | AI features | | ruff | Formatting | | nbformat>=5.7.0 | Export as IPYNB | | vegafusion>=2.0.0 | Performant charting | | vl-convert-python>=1.0.0 | Required by vegafusion | Readings & Videos - marimo https://docs.marimo.io/reading/ Resources[¶](#resources "Permanent link") ----------------------------------------- marimo is a **reinvention** of the Python notebook. As a reinvention, marimo may push to you **rethink** what a notebook **is**. The following readings and videos might help you do just that. To dive deep into what we're building and why, check out these readings: * [Our HackerNews launch, the second most upvoted Python ShowHN of all time](https://news.ycombinator.com/item?id=38971966) * [Our r/machinelearning launch](https://www.reddit.com/r/MachineLearning/comments/191rdwq/p_i_built_marimo_an_opensource_reactive_python/) * [Lessons Learned Reinventing the Python Notebook](https://marimo.io/blog/lessons-learned) * [Why Stanford Scientists Needed a New Notebook](https://marimo.io/blog/slac-marimo) * [Reinventing Python Notebooks as Reusable Python Programs](https://marimo.io/blog/python-not-json) * [Representing Python Notebooks as Dataflow Graphs](https://marimo.io/blog/dataflow) * [Nature: a Notebook for Reproducible Code](https://www.nature.com/articles/d41586-025-01241-6) See [our blog](https://marimo.io/blog) for more. YouTube[¶](#youtube "Permanent link") ------------------------------------- Our [YouTube channel](https://www.youtube.com/@marimo-team) shows you the ins and outs of using marimo for many applications, including AI, ML, data engineering, and more. You can also get started with the [marimo concepts](https://www.youtube.com/watch?v=3N6lInzq5MI&list=PLNJXGo8e1XT9jP7gPbRdm1XwloZVFvLEq) playlist, which tours many of our features. You may also enjoy this video, which highlights some of the more advanced features that can really help you get the most out of marimo. Key Concepts - marimo https://docs.marimo.io/getting_started/key_concepts/ This page covers marimo's key concepts: * marimo lets you rapidly experiment with data using Python, SQL, and interactive elements in a reproducible **notebook environment**. * Unlike Jupyter notebooks, marimo notebooks are reusable software artifacts. marimo notebooks can be shared as as **interactive web apps** and executed as **Python scripts**. Editing notebooks[¶](#editing-notebooks "Permanent link") --------------------------------------------------------- marimo notebooks are **reactive**: they automatically react to your code changes and UI interactions and keep your notebook up-to-date, not unlike a spreadsheet. This makes your notebooks reproducible, [eliminating hidden state](https://docs.marimo.io/faq/#faq-problems); it's also what enables marimo notebooks to double as apps and Python scripts. Working with expensive notebooks If you don't want cells to run automatically, the [runtime can be configured](https://docs.marimo.io/guides/configuration/runtime_configuration/) to be lazy, only running cells when you ask for them to be run and marking affected cells as stale. **See our guide on working with [expensive notebooks](https://docs.marimo.io/guides/expensive_notebooks/) for more tips.** **Create your first notebook.** After [installing marimo](https://docs.marimo.io/getting_started/installation/), create your first notebook with `[](#__codelineno-0-1)marimo edit my_notebook.py` at the command-line. **The marimo library**. We recommend starting each marimo notebook with a cell containing a single line of code, The marimo library lets you use interactive UI elements, layout elements, dynamic markdown, and more in your marimo notebooks. ### How marimo executes cells[¶](#how-marimo-executes-cells "Permanent link") A marimo notebook is made of small blocks of Python code called **cells**. _When you run a cell, marimo automatically runs all cells that read any global variables defined by that cell._ This is reactive execution. **Execution order.** The order of cells on the page has no bearing on the order cells are executed in: execution order is determined by the variables cells define and the variables they read. You have full freedom over how to organize your code and tell your stories: move helper functions and other "appendices" to the bottom of your notebook, or put cells with important outputs at the top. **No hidden state.** marimo notebooks have no hidden state because the program state is automatically synchronized with your code changes and UI interactions. And if you delete a cell, marimo automatically deletes that cell's variables, preventing painful bugs that arise in traditional notebooks. **No magical syntax.** There's no magical syntax or API required to opt-in to reactivity: cells are Python and _only Python_. Behind-the-scenes, marimo statically analyzes each cell's code just once, creating a directed acyclic graph based on the global names each cell defines and reads. This is how data flows in a marimo notebook. Minimize variable mutation. marimo's understanding of your code is based on variable definitions and references; marimo does not track mutations to objects at runtime. For this reason, if you need to mutate a variable (such as adding a new column to a dataframe), you should perform the mutation in the same cell as the one that defines it. Learn more in our [reactivity guide](https://docs.marimo.io/guides/reactivity/#reactivity-mutations). For more on reactive execution, open the dataflow tutorial or read the [reactivity guide](https://docs.marimo.io/guides/reactivity/). To visualize and understand how data flows through your notebook, check out our [dataflow tools](https://docs.marimo.io/guides/editor_features/dataflow/). ### Visualizing outputs[¶](#visualizing-outputs "Permanent link") marimo visualizes the last expression of each cell as its **output**. Outputs can be any Python value, including markdown and interactive elements created with the marimo library, (_e.g._, [`mo.md`](https://docs.marimo.io/api/markdown/#marimo.md " marimo.md"), [`mo.ui.slider`](https://docs.marimo.io/api/inputs/slider/#marimo.ui.slider " marimo.ui.slider")). You can even interpolate Python values into markdown (using `mo.md(f"...")`) and other marimo elements to build rich composite outputs: > Thanks to reactive execution, running a cell refreshes all the relevant outputs in your notebook. The marimo library also comes with elements for laying out outputs, including [`mo.hstack`](https://docs.marimo.io/api/layouts/stacks/#marimo.hstack " marimo.hstack"), [`mo.vstack`](https://docs.marimo.io/api/layouts/stacks/#marimo.vstack " marimo.vstack"), [`mo.accordion`](https://docs.marimo.io/api/layouts/accordion/#marimo.accordion " marimo.accordion"), [`mo.ui.tabs`](https://docs.marimo.io/api/inputs/tabs/#marimo.ui.tabs " marimo.ui.tabs"), [`mo.sidebar`](https://docs.marimo.io/api/layouts/sidebar/#marimo.sidebar " marimo.sidebar"), [`mo.nav_menu`](https://docs.marimo.io/api/inputs/nav_menu/#marimo.nav_menu " marimo.nav_menu"), [`mo.ui.table`](https://docs.marimo.io/api/inputs/table/#marimo.ui.table " marimo.ui.table"), and [many more](https://docs.marimo.io/api/layouts/). For more on outputs, try these tutorials: `[](#__codelineno-3-1)marimo tutorial markdown [](#__codelineno-3-2)marimo tutorial plots [](#__codelineno-3-3)marimo tutorial layout` or read the [visualizing outputs guide](https://docs.marimo.io/guides/outputs/). ### Creating interactive elements[¶](#creating-interactive-elements "Permanent link") The marimo library comes with many interactive stateful elements in [`marimo.ui`](https://docs.marimo.io/api/inputs/), including simple ones like sliders, dropdowns, text fields, and file upload areas, as well as composite ones like forms, arrays, and dictionaries that can wrap other UI elements. **Using UI elements.** To use a UI element, create it with `mo.ui` and **assign it to a global variable.** When you interact with a UI element in your browser (_e.g._, sliding a slider), _marimo sends the new value back to Python and reactively runs all cells that use the element_, which you can access via its `value` attribute. > **This combination of interactivity and reactivity is very powerful**: use it to make your data tangible during exploration and to build all kinds of tools and apps. _marimo can only synchronize UI elements that are assigned to global variables._ Use composite elements like [`mo.ui.array`](https://docs.marimo.io/api/inputs/array/#marimo.ui.array " marimo.ui.array") and [`mo.ui.dictionary`](https://docs.marimo.io/api/inputs/dictionary/#marimo.ui.dictionary " marimo.ui.dictionary") if the set of UI elements is not known until runtime. Using buttons to execute cells Use [`mo.ui.run_button`](https://docs.marimo.io/api/inputs/run_button/#marimo.ui.run_button " marimo.ui.run_button") to create a button that triggers computation when clicked; see our recipes for [an example](https://docs.marimo.io/recipes/#create-a-button-that-triggers-computation-when-clicked). For more on interactive elements, run the UI tutorial or read the [interactivity guide](https://docs.marimo.io/guides/interactivity/). ### Querying dataframes and databases with SQL[¶](#querying-dataframes-and-databases-with-sql "Permanent link") marimo has built-in support for SQL: you can query Python dataframes, databases, CSVs, Google Sheets, or anything else. After executing your query, marimo returns the result to you as a dataframe, making it seamless to go back and forth between SQL and Python. Query a dataframe using SQL! To create a SQL cell, click on the SQL button that appears at the bottom of the cell array, or right click the create cell button next to a cell. Today, SQL in marimo is executed using [duckdb](https://duckdb.org/docs/). To learn more, run the SQL tutorial or read the [SQL guide](https://docs.marimo.io/guides/working_with_data/sql/). Running notebooks as applications[¶](#running-notebooks-as-applications "Permanent link") ----------------------------------------------------------------------------------------- You can use marimo as a notebook, similar to how you might use Jupyter. But you can also do more: because marimo notebooks are reactive and can include interactive elements, hiding notebook code gives you a simple web app! You can run your notebook as a read-only web app from the command-line: `[](#__codelineno-6-1)marimo run my_notebook.py` The default renderer just hides the notebook code and concatenates outputs vertically. But marimo also supports [other layouts](https://docs.marimo.io/guides/apps/), such as slides and grid. Running notebooks as scripts[¶](#running-notebooks-as-scripts "Permanent link") ------------------------------------------------------------------------------- Because marimo notebooks are stored as pure Python files, each notebook can be executed as a script from the command-line: You can also [pass command-line arguments](https://docs.marimo.io/guides/scripts/) to scripts. Running cells - marimo https://docs.marimo.io/guides/reactivity/ marimo _reacts_ to your code changes: run a cell, and all other cells that refer to the variables it defines are automatically run with the latest data. This keeps your code and outputs consistent, and eliminates bugs before they happen. Why run cells reactively? marimo's "reactive" execution model makes your notebooks more reproducible by eliminating hidden state and providing a deterministic execution order. It also powers marimo's support for [interactive elements](https://docs.marimo.io/guides/interactivity/), for running as apps, and executing as scripts. How marimo runs cells is one of the biggest differences between marimo and traditional notebooks like Jupyter. Learn more at our [FAQ](https://docs.marimo.io/faq/#faq-jupyter). Working with expensive notebooks marimo provides tools for working with expensive notebooks, in which cells might take a long time to run or have side-effects. * The [runtime can be configured](https://docs.marimo.io/guides/configuration/runtime_configuration/) to be **lazy** instead of automatic, marking cells as stale instead of running them. * Use [`mo.stop`](https://docs.marimo.io/api/control_flow/#marimo.stop " marimo.stop") to conditionally stop execution at runtime. See [the expensive notebooks guide](https://docs.marimo.io/guides/expensive_notebooks/) for more tips. How marimo runs cells[¶](#how-marimo-runs-cells "Permanent link") ----------------------------------------------------------------- marimo statically analyzes each cell (i.e., without running it) to determine its * references, the global variables it reads but doesn't define; * definitions, the global variables it defines. It then forms a directed acyclic graph (DAG) on cells, with an edge from one cell to another if the latter references any of the definitions of the former. When a cell is run, its descendants are marked for execution. Runtime Rule When a cell is run, marimo automatically runs all other cells that **reference** any of the global variables it **defines**. marimo [does not track mutations](#variable-mutations-are-not-tracked) to variables, nor assignments to attributes. That means that if you assign an attribute like `foo.bar = 10`, other cells referencing `foo.bar` will _not_ be run. ### Execution order[¶](#execution-order "Permanent link") The order cells are executed in is determined by the relationships between cells and their variables, not by the order of cells on the page (similar to a spreadsheet). This lets you organize your code in whatever way makes the most sense to you. For example, you can put helper functions at the bottom of your notebook. ### Deleting a cell deletes its variables[¶](#deleting-a-cell-deletes-its-variables "Permanent link") In marimo, _deleting a cell deletes its global variables from program memory_. Cells that previously referenced these variables are automatically re-run and invalidated (or marked as stale, depending on your [runtime configuration](https://docs.marimo.io/guides/configuration/runtime_configuration/)). In this way, marimo eliminates a common cause of bugs in traditional notebooks like Jupyter. ### Variable mutations are not tracked[¶](#variable-mutations-are-not-tracked "Permanent link") marimo does not track mutations to objects, _e.g._, mutations like `my_list.append(42)` or `my_object.value = 42` don't trigger reactive re-runs of other cells. **Avoid defining a variable in one cell and mutating it in another**. Why not track mutations? Tracking mutations reliably is impossible in Python. Reacting to mutations could result in surprising re-runs of notebook cells. If you need to mutate a variable (such as adding a new column to a dataframe), you should perform the mutation in the same cell as the one that defines it, or try creating a new variable instead. Create new variables, don't mutate existing ones Mutate variables in the cells that define them Do this ...... not this `[](#__codelineno-4-1)df = pd.DataFrame({"my_column": [1, 2]}) [](#__codelineno-4-2)df["another_column"] = [3, 4]` `[](#__codelineno-5-1)df = pd.DataFrame({"my_column": [1, 2]})` `[](#__codelineno-6-1)df["another_column"] = [3, 4]` Global variable names must be unique[¶](#global-variable-names-must-be-unique "Permanent link") ----------------------------------------------------------------------------------------------- **marimo requires that every global variable be defined by only one cell.** This lets marimo keep code and outputs consistent. Global variables A variable can refer to any Python object. Functions, classes, and imported names are all variables. This rule encourages you to keep the number of global variables in your program small, which is generally considered good practice. ### Creating temporary variables[¶](#creating-temporary-variables "Permanent link") marimo provides two ways to define temporary variables, which can help keep the number of global variables in your notebook small. #### Creating local variables[¶](#creating-local-variables "Permanent link") Variables prefixed with an underscore (_e.g._, `_x`) are "local" to a cell: they can't be read by other cells. Multiple cells can reuse the same local variables names. #### Encapsulating code in functions[¶](#encapsulating-code-in-functions "Permanent link") If you want most or all the variables in a cell to be temporary, prefixing each variable with an underscore to make it local may feel inconvenient. In these situations we recommend encapsulating the temporary variables in a function. For example, if you find yourself copy-pasting the same plotting code across multiple cells and only tweaking a few parameters, try the following pattern: `[](#__codelineno-7-1)def _(): [](#__codelineno-7-2) import matplotlib.pyplot as plt [](#__codelineno-7-3) fig, ax = plt.subplots() [](#__codelineno-7-4) ax.plot([1, 2]) [](#__codelineno-7-5) return ax [](#__codelineno-7-6)[](#__codelineno-7-7)_()` Here, the variables `plt`, `fig`, and `ax` aren't added to the globals. ### Managing memory[¶](#managing-memory "Permanent link") Because variable names must be unique, you cannot reassign variables as a means of freeing memory. Instead, manage memory by encapsulating code in functions or using the `del` operator. See our guide on [expensive notebooks](https://docs.marimo.io/guides/expensive_notebooks/#manage-memory) to learn more. Configuring how marimo runs cells[¶](#configuring-how-marimo-runs-cells "Permanent link") ----------------------------------------------------------------------------------------- Through the notebook settings menu, you can configure how and when marimo runs cells. In particular, you can disable autorun on startup, disable autorun on cell execution, and enable a module autoreloader. Read our [runtime configuration guide](https://docs.marimo.io/guides/configuration/runtime_configuration/) to learn more. Disabling cells[¶](#disabling-cells "Permanent link") ----------------------------------------------------- Sometimes, you may want to edit one part of a notebook without triggering automatic execution of its dependent cells. For example, the dependent cells may take a long time to execute, and you only want to iterate on the first part of a multi-cell computation. For cases like this, marimo lets you **disable** cells: when a cell is disabled, it and its dependents are blocked from running. Disabling a cell blocks it from running. When you re-enable a cell, if any of the cell's ancestors ran while it was disabled, marimo will automatically run it. Enable a cell through the context menu. Stale cells run automatically. Interactive elements - marimo https://docs.marimo.io/guides/interactivity/ One of marimo's most powerful features is its first-class support for interactive user interface (UI) elements, or "widgets", created using [`marimo.ui`](https://docs.marimo.io/api/inputs/). **Interacting with a UI element bound to a global variable automatically runs all cells that reference it.** How interactions run cells[¶](#how-interactions-run-cells "Permanent link") --------------------------------------------------------------------------- Every UI element you make using [`marimo.ui`](https://docs.marimo.io/api/inputs/) has a value, accessible via its `value` attribute. When you interact with a UI element bound to a global variable, its value is sent back to Python. A single rule determines what happens next: Interaction rule When a UI element assigned to a global variable is interacted with, marimo automatically runs all cells that reference the variable (but don't define it). In the clip at the top of this page, interacting with the slider in the second cell re-runs the third cell (which outputs markdown) because it references the slider variable `x`. It doesn't re-run the second cell, because that cell defines `x`. **For interactions on a UI element to have any effect, the element must be assigned to a global variable.** Displaying UI elements[¶](#displaying-ui-elements "Permanent link") ------------------------------------------------------------------- Display UI elements in the output area above a cell by including them in the last expression, just like any other object. You can also embed elements in [markdown](https://docs.marimo.io/api/markdown/#marimo.md " marimo.md") using Python f-strings, like so: `[](#__codelineno-0-1)slider = mo.ui.slider(1, 10) [](#__codelineno-0-2)mo.md(f"Choose a value: {slider}")` Composite elements[¶](#composite-elements "Permanent link") ----------------------------------------------------------- Composite elements are advanced elements let you build UI elements out of other UI elements. The following composite elements are available: * [`mo.ui.array`](https://docs.marimo.io/api/inputs/array/#marimo.ui.array " marimo.ui.array") * [`mo.ui.dictionary`](https://docs.marimo.io/api/inputs/dictionary/#marimo.ui.dictionary " marimo.ui.dictionary") * [`mo.ui.batch`](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch") * [`mo.ui.form`](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form") **Arrays and dictionaries.** Use [`mo.ui.array`](https://docs.marimo.io/api/inputs/array/#marimo.ui.array " marimo.ui.array") and [`mo.ui.dictionary`](https://docs.marimo.io/api/inputs/dictionary/#marimo.ui.dictionary " marimo.ui.dictionary") to logically group together related elements. These elements are especially useful when a set of UI elements is only known at runtime (so you can't assign each to a global variable individually, but can assign them to an array or dictionary). You can access the elements contained in an array or dictionary using Pythonic syntax, and embed these elements in other outputs. See their docstrings for code examples. **Batch and form.** Use these powerful elements to group together multiple UI elements into a single element with custom formatting, and gate the sending of an element's value on form submission. Use a form to gate value updates on submission Use an array to group together elements or create a collection of elements that is determined at runtime Building custom UI elements using our plugin API[¶](#building-custom-ui-elements-using-our-plugin-api "Permanent link") ----------------------------------------------------------------------------------------------------------------------- You can build your own reactive and interactive UI elements using [anywidget](https://github.com/manzt/anywidget). See [our docs on building custom UI elements](https://docs.marimo.io/guides/integrating_with_marimo/custom_ui_plugins/) to learn more. Quickstart - marimo https://docs.marimo.io/getting_started/quickstart/ Installing marimo gets you the `marimo` command-line interface (CLI), the entry point to all things marimo. Run tutorials[¶](#run-tutorials "Permanent link") ------------------------------------------------- `marimo tutorial intro` opens the intro tutorial. List all tutorials with Edit notebooks[¶](#edit-notebooks "Permanent link") --------------------------------------------------- Create and edit notebooks with `marimo edit`. * launch the notebook server to create new notebooks, and start or stop existing ones: * create or edit a single notebook with `[](#__codelineno-2-1)marimo edit your_notebook.py` (If `your_notebook.py` doesn't exist, marimo will create a blank notebook named `your_notebook.py`.) Deploy as apps[¶](#deploy-as-apps "Permanent link") --------------------------------------------------- Use `marimo run` to [serve your notebook as an app](https://docs.marimo.io/guides/apps/), with Python code hidden and uneditable. `[](#__codelineno-3-1)marimo run your_notebook.py` Run as scripts[¶](#run-as-scripts "Permanent link") --------------------------------------------------- Run your notebook as a script with You can also [pass CLI args](https://docs.marimo.io/guides/scripts/) to your notebook. Convert Jupyter notebooks and Python scripts to marimo[¶](#convert-jupyter-notebooks-and-python-scripts-to-marimo "Permanent link") ----------------------------------------------------------------------------------------------------------------------------------- Automatically convert Jupyter notebooks and Python scripts to marimo notebooks with `marimo convert`: `[](#__codelineno-5-1)# From Jupyter notebook [](#__codelineno-5-2)marimo convert your_notebook.ipynb -o your_notebook.py [](#__codelineno-5-3)[](#__codelineno-5-4)# From Python script or jupytext py:percent format [](#__codelineno-5-5)marimo convert your_script.py -o your_notebook.py` Then open the notebook with `marimo edit your_notebook.py` Disable autorun on startup marimo automatically runs notebooks when they are opened. If this is a problem for you (not all Jupyter notebooks are designed to be run on startup), you can disable autorun on startup via [user configuration](https://docs.marimo.io/guides/configuration/runtime_configuration/). 1. Type `marimo config show` to get the location of your config file. 2. If no config file exists, create it at `$XDG_CONFIG_HOME/marimo/marimo.toml`. 3. Update your config to include the following: marimo.toml `[](#__codelineno-6-1)[runtime] [](#__codelineno-6-2)auto_instantiate = false` Export marimo notebooks to other file formats[¶](#export-marimo-notebooks-to-other-file-formats "Permanent link") ----------------------------------------------------------------------------------------------------------------- Use to [export marimo notebooks](https://docs.marimo.io/guides/exporting/) to other file formats, including HTML, IPYNB, and markdown. Install optional dependencies for more features[¶](#install-optional-dependencies-for-more-features "Permanent link") --------------------------------------------------------------------------------------------------------------------- Some features require additional dependencies, which are not installed by default. This includes: * [SQL cells](https://docs.marimo.io/guides/working_with_data/sql/) * Charts in the datasource viewer * [AI features](https://docs.marimo.io/guides/editor_features/ai_completion/) * Format on save To install the optional dependencies, run: install with pipinstall with uvinstall with conda `[](#__codelineno-8-1)pip install "marimo[recommended]"` `[](#__codelineno-9-1)uv add "marimo[recommended]"` `[](#__codelineno-10-1)conda install -c conda-forge marimo duckdb altair polars openai ruff` This will install: `duckdb`, `altair`, `polars`, `openai`, and `ruff`. Enable GitHub Copilot and AI Assistant[¶](#enable-github-copilot-and-ai-assistant "Permanent link") --------------------------------------------------------------------------------------------------- The marimo editor natively supports [GitHub Copilot](https://copilot.github.com/), an AI pair programmer, similar to VS Code. _Get started with Copilot_: 1. Install [Node.js](https://nodejs.org/en/download). 2. Enable Copilot via the settings menu in the marimo editor. _Note_: Copilot is not yet available in our conda distribution; please install marimo from `PyPI` if you need Copilot. marimo also comes with support for [other copilots](https://docs.marimo.io/guides/editor_features/ai_completion/#custom-copilots), and a built-in [AI assistant](https://docs.marimo.io/guides/editor_features/ai_completion/) that helps you write code. Use [molab](https://molab.marimo.io/notebooks), a cloud-based marimo notebook service similar to Google Colab, to create and share notebook links ([docs](https://docs.marimo.io/guides/molab/)). VS Code/Cursor extension[¶](#vs-codecursor-extension "Permanent link") ---------------------------------------------------------------------- You can edit and run marimo notebooks in VS Code or Cursor using our extension; this provides a user interface that's similar to VS Code Jupyter, but with marimo's reactive execution, interactive elements, built-in package management, Git-friendly file format, and more. Install the extension by searching "marimo" in the extensions sidebar (`Cmd/Ctrl-Shift-P`, type "install extension", then search "marimo") or from the [VS Code marketplace site](https://marketplace.visualstudio.com/items?itemName=marimo-team.vscode-marimo). Working with data - marimo https://docs.marimo.io/guides/working_with_data/ These guides introduce you to marimo's features for working with data, including SQL cells, no-code dataframe transformation tools, plots whose selections are automatically sent back to Python, and browsing remote storage. | Guide | Description | | --- | --- | | [SQL](https://docs.marimo.io/guides/working_with_data/sql/) | Use SQL to query dataframes, databases, CSVs, etc. | | [Dataframes](https://docs.marimo.io/guides/working_with_data/dataframes/) | Filter, search, and transform dataframes without code | | [Plotting](https://docs.marimo.io/guides/working_with_data/plotting/) | Send plot selections to Python | | [Remote Storage](https://docs.marimo.io/guides/working_with_data/remote_storage/) | Browse and download files from S3, GCS, Azure, and more | Visualize outputs - marimo https://docs.marimo.io/guides/outputs/ Visualizing outputs[¶](#visualizing-outputs "Permanent link") ------------------------------------------------------------- The last expression of a cell is its visual output, rendered above the cell. Outputs are included in the "app" or read-only view of the notebook. marimo comes out of the box a number of elements to help you make rich outputs, documented in the [API reference](https://docs.marimo.io/api/). Markdown[¶](#markdown "Permanent link") --------------------------------------- Markdown is written with the marimo library function [`mo.md`](https://docs.marimo.io/api/markdown/#marimo.md " marimo.md"). Writing markdown programmatically lets you make dynamic markdown: interpolate Python values into markdown strings, conditionally render your markdown, and embed markdown in other objects. Here's a simple hello world example: `[](#__codelineno-1-1)name = mo.ui.text(placeholder="Your name here") [](#__codelineno-1-2)mo.md( [](#__codelineno-1-3) f""" [](#__codelineno-1-4) Hi! What's your name? [](#__codelineno-1-5) [](#__codelineno-1-6) {name} [](#__codelineno-1-7) """ [](#__codelineno-1-8))` `[](#__codelineno-2-1)mo.md( [](#__codelineno-2-2) f""" [](#__codelineno-2-3) Hello, {name.value}! [](#__codelineno-2-4) """ [](#__codelineno-2-5))` Notice that marimo knows how to render marimo objects in markdown: you can just embed them in [`mo.md()`](https://docs.marimo.io/api/markdown/#marimo.md " marimo.md") using an f-string, and marimo will figure out how to display them! For other objects, like matplotlib plots, wrap them in [`mo.as_html()`](https://docs.marimo.io/api/html/#marimo.as_html " marimo.as_html") to tap into marimo's media viewer: `[](#__codelineno-3-1)mo.md( [](#__codelineno-3-2) f""" [](#__codelineno-3-3) Here's a plot! [](#__codelineno-3-4) [](#__codelineno-3-5) {mo.as_html(figure)} [](#__codelineno-3-6) """ [](#__codelineno-3-7))` ### Markdown editor[¶](#markdown-editor "Permanent link") marimo automatically renders cells that only use `mo.md` in a markdown editor that supports common hotkeys. You can switch between the Markdown and Python editors by clicking the button in the top right: marimo is pure Python, even when you're using markdown. **Writing LaTeX.** The markdown editor supports writing LaTeX. You should typically use a raw string for markdown with LaTeX, which you can activate by checking the `r` box in the bottom-right corner of the markdown editor. **Interpolating Python values.** Interpolating Python values requires using an `f`\-string, which you can activate by checking the `f` box in the bottom-right corner of the markdown editor. ### Markdown extensions[¶](#markdown-extensions "Permanent link") #### Details[¶](#details "Permanent link") Create expandable details with additional context: `[](#__codelineno-4-1)/// details | Heads up [](#__codelineno-4-2)[](#__codelineno-4-3)Here's some additional context. [](#__codelineno-4-4)///` Source code for `examples/markdown/details.py` Tip: paste this code into an empty cell, and the marimo editor will create cells for you ``import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell(hide_code=True) def _(mo): mo.md(r""" Create expandable markdown blocks with `details`: """) return @app.cell def _(mo): mo.md(""" /// details | Hello, details! Some additional content. /// """) return @app.cell(hide_code=True) def _(mo): mo.md(r""" Style details using the "type" argument: """) return @app.cell def _(mo): mo.md(""" /// details | Info details type: info Some additional content. /// """) return @app.cell def _(mo): mo.md(""" /// details | Warning details type: warn This highlights something to watch out for /// """) return @app.cell def _(mo): mo.md(""" /// details | Danger details type: danger This indicates a critical warning or dangerous situation /// """) return @app.cell def _(mo): mo.md(""" /// details | Success details type: success This indicates a successful outcome or positive note /// """) return @app.cell def _(): import marimo as mo return (mo,) if __name__ == "__main__": app.run()`` #### Admonitions[¶](#admonitions "Permanent link") Highlight text using admonitions: `[](#__codelineno-5-1)/// attention | This is important. [](#__codelineno-5-2)[](#__codelineno-5-3)Pay attention to this text! [](#__codelineno-5-4)///` Source code for `examples/markdown/admonitions.py` Tip: paste this code into an empty cell, and the marimo editor will create cells for you `import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell(hide_code=True) def _(mo): mo.md(r""" Use **admonitions** in markdown to bring attention to text. Here are some examples. """) return @app.cell def _(mo): mo.md(""" /// admonition | Heads up. Here's some information. /// """) return @app.cell def _(mo): mo.md(""" /// attention | Attention! This is important. /// """) return @app.cell def _(): import marimo as mo return (mo,) if __name__ == "__main__": app.run()` #### Emoji[¶](#emoji "Permanent link") Use `:emoji:` syntax to add emojis; for example, `:rocket:` creates 🚀. ### Static files[¶](#static-files "Permanent link") marimo supports serving static files from a `public/` folder located next to your notebook. This is useful for including images or other static assets in your notebook. To use files from the public folder, create a `public` directory next to your notebook and reference files using the `public/` path prefix: `[](#__codelineno-6-1)mo.md( [](#__codelineno-6-2) ''' [](#__codelineno-6-3) [](#__codelineno-6-4) [](#__codelineno-6-5) or [](#__codelineno-6-6) [](#__codelineno-6-7) ![alt text](public/image.png) [](#__codelineno-6-8) ''' [](#__codelineno-6-9))` For security reasons: * Only files within the `public` directory can be accessed * Symlinks are not followed * Path traversal attempts (e.g., `../`) are blocked Layout[¶](#layout "Permanent link") ----------------------------------- The marimo library also comes with elements for laying out outputs, including [`mo.hstack`](https://docs.marimo.io/api/layouts/stacks/#marimo.hstack " marimo.hstack"), [`mo.vstack`](https://docs.marimo.io/api/layouts/stacks/#marimo.vstack " marimo.vstack"), [`mo.accordion`](https://docs.marimo.io/api/layouts/accordion/#marimo.accordion " marimo.accordion"), [`mo.ui.tabs`](https://docs.marimo.io/api/inputs/tabs/#marimo.ui.tabs " marimo.ui.tabs"), [`mo.sidebar`](https://docs.marimo.io/api/layouts/sidebar/#marimo.sidebar " marimo.sidebar"), [`mo.nav_menu`](https://docs.marimo.io/api/inputs/nav_menu/#marimo.nav_menu " marimo.nav_menu"), [`mo.ui.table`](https://docs.marimo.io/api/inputs/table/#marimo.ui.table " marimo.ui.table"), and [many more](https://docs.marimo.io/api/layouts/). Progress bars[¶](#progress-bars "Permanent link") ------------------------------------------------- Use [`mo.status.progress_bar`](https://docs.marimo.io/api/status/#marimo.status.progress_bar " marimo.status.progress_bar") and [`mo.status.spinner`](https://docs.marimo.io/api/status/#marimo.status.spinner " marimo.status.spinner") to create progress indicators: `[](#__codelineno-7-1)# mo.status.progress_bar is similar to TQDM [](#__codelineno-7-2)for i in mo.status.progress_bar(range(10)): [](#__codelineno-7-3) print(i)` marimo comes with functions to display media, including images, audio, video, pdfs, and more. See the [API docs](https://docs.marimo.io/api/media/) for more info. Inspecting objects[¶](#inspecting-objects "Permanent link") ----------------------------------------------------------- marimo has built-in formatters for many objects, but sometimes the default representation isn't useful (e.g., ``). In these cases, use [`mo.inspect()`](https://docs.marimo.io/api/miscellaneous/#marimo.inspect " marimo.inspect") to explore an object's attributes, methods, and documentation as an output. See the [API docs](https://docs.marimo.io/api/outputs/#object-inspection) for more details. Imperatively adding outputs[¶](#imperatively-adding-outputs "Permanent link") ----------------------------------------------------------------------------- While a cell's output is its last expression, it can at times be helpful to imperatively add to the output area while a cell is running. marimo provides utility functions like [`mo.output.append`](https://docs.marimo.io/api/outputs/#marimo.output.append " marimo.output.append") for accomplishing this; see the [API docs](https://docs.marimo.io/api/outputs/) for more information. Console Outputs[¶](#console-outputs "Permanent link") ----------------------------------------------------- Console outputs, such as print statements, show up below a cell in the console output area; they are not included in the output area or app view by default. To include console outputs in the cell output area, use [`mo.redirect_stdout`](https://docs.marimo.io/api/outputs/#marimo.redirect_stdout " marimo.redirect_stdout") or [`mo.redirect_stderr`](https://docs.marimo.io/api/outputs/#marimo.redirect_stderr " marimo.redirect_stderr"): `[](#__codelineno-8-1)with mo.redirect_stdout(): [](#__codelineno-8-2) print("Hello, world!")` marimo also includes utility functions for [capturing standard out](https://docs.marimo.io/api/outputs/#marimo.capture_stdout " marimo.capture_stdout") and [standard error](https://docs.marimo.io/api/outputs/#marimo.capture_stderr " marimo.capture_stderr") without redirecting them. See the [API docs](https://docs.marimo.io/api/outputs/#console-outputs) for more. Threading[¶](#threading "Permanent link") ----------------------------------------- To create a thread that can reliably communicate outputs to the frontend, use [`mo.Thread`](https://docs.marimo.io/api/control_flow/#marimo.Thread " marimo.Thread"), which has exactly the same API as as `threading.Thread`. ### Cleaning up your thread[¶](#cleaning-up-your-thread "Permanent link") When the cell that spawned a [`mo.Thread`](https://docs.marimo.io/api/control_flow/#marimo.Thread " marimo.Thread") is invalidated (re-run, deleted, interrupted, or otherwise errored), the thread's `should_exit` property will evaluate to `True`, at which point it is your responsibility to clean up your thread. You can retrieve the current [`mo.Thread`](https://docs.marimo.io/api/control_flow/#marimo.Thread " marimo.Thread") with [`mo.current_thread`](https://docs.marimo.io/api/control_flow/#marimo.current_thread " marimo.current_thread"). **Example.** `[](#__codelineno-9-1)def target(): [](#__codelineno-9-2) import marimo as mo [](#__codelineno-9-3) [](#__codelineno-9-4) thread = mo.current_thread() [](#__codelineno-9-5) while not thread.should_exit: [](#__codelineno-9-6) ...` ### Patching threads created by third-party code[¶](#patching-threads-created-by-third-party-code "Permanent link") If you need to forward outputs from threads spawned by third-party code, try patching `threading.Thread`: `[](#__codelineno-10-1)import threading [](#__codelineno-10-2)import marimo as mo [](#__codelineno-10-3)[](#__codelineno-10-4)threading.Thread = mo.Thread` This however may leak threads, since the patched threads won't know to check the `mo.Thread`'s `should_exit` property. DataFrames - marimo https://docs.marimo.io/guides/working_with_data/dataframes/ Interactive dataframes[¶](#interactive-dataframes "Permanent link") ------------------------------------------------------------------- **marimo makes you more productive when working with dataframes**. * [Display dataframes](#displaying-dataframes) in a rich, interactive table and chart views * [Transform dataframes](#transforming-dataframes) with filters, groupbys, aggregations, and more, **no code required** * [Select data](#selecting-dataframes) from tables or charts and get selections back in Python as dataframes _marimo integrates with [Pandas](https://pandas.pydata.org/) and [Polars](https://pola.rs/) dataframes natively_. For a video overview on interactive dataframes, check out our [YouTube tutorial](https://www.youtube.com/watch?v=ZTs7vHzsqlQ). Displaying dataframes[¶](#displaying-dataframes "Permanent link") ----------------------------------------------------------------- marimo lets you page through, search, sort, and filter dataframes, making it extremely easy to get a feel for your data. marimo brings dataframes to life. Display dataframes by including them in the last expression of the cell, just like any other object. pandaspolarslive example `[](#__codelineno-0-1)import pandas as pd [](#__codelineno-0-2)[](#__codelineno-0-3)df = pd.read_json( [](#__codelineno-0-4) "https://raw.githubusercontent.com/vega/vega-datasets/master/data/cars.json" [](#__codelineno-0-5)) [](#__codelineno-0-6)df` `[](#__codelineno-1-1)import polars as pl [](#__codelineno-1-2)[](#__codelineno-1-3)df = pl.read_json( [](#__codelineno-1-4)"https://raw.githubusercontent.com/vega/vega-datasets/master/data/cars.json" [](#__codelineno-1-5)) [](#__codelineno-1-6)df` To opt out of the rich dataframe viewer, use [`mo.plain`](https://docs.marimo.io/api/layouts/plain/#marimo.plain " marimo.plain"): pandaspolarslive example `[](#__codelineno-3-1)import pandas as pd [](#__codelineno-3-2)import marimo as mo [](#__codelineno-3-3)[](#__codelineno-3-4)df = pd.read_json( [](#__codelineno-3-5)"https://raw.githubusercontent.com/vega/vega-datasets/master/data/cars.json" [](#__codelineno-3-6)) [](#__codelineno-3-7)mo.plain(df)` `[](#__codelineno-4-1)import polars as pl [](#__codelineno-4-2)import marimo as mo [](#__codelineno-4-3)[](#__codelineno-4-4)df = pl.read_json( [](#__codelineno-4-5)"https://raw.githubusercontent.com/vega/vega-datasets/master/data/cars.json" [](#__codelineno-4-6)) [](#__codelineno-4-7)mo.plain(df)` Transforming dataframes[¶](#transforming-dataframes "Permanent link") --------------------------------------------------------------------- ### No-code transformations[¶](#no-code-transformations "Permanent link") Use [`mo.ui.dataframe`](https://docs.marimo.io/api/inputs/dataframe/#marimo.ui.dataframe " marimo.ui.dataframe") to interactively transform a dataframe with a GUI, no coding required. When you're done, you can copy the code that the GUI generated for you and paste it into your notebook. Build transformations using a GUI The transformations you apply will turn into code which is accessible via the "code" tab. Copy the code of the transformation pandaspolarslive example `[](#__codelineno-6-1)# Cell 1 [](#__codelineno-6-2)import marimo as mo [](#__codelineno-6-3)import pandas as pd [](#__codelineno-6-4)[](#__codelineno-6-5)df = pd.DataFrame({"person": ["Alice", "Bob", "Charlie"], "age": [20, 30, 40]}) [](#__codelineno-6-6)transformed_df = mo.ui.dataframe(df) [](#__codelineno-6-7)transformed_df` `[](#__codelineno-7-1)# Cell 2 [](#__codelineno-7-2)# transformed_df.value holds the transformed dataframe [](#__codelineno-7-3)transformed_df.value` `[](#__codelineno-8-1)# Cell 1 [](#__codelineno-8-2)import marimo as mo [](#__codelineno-8-3)import polars as pl [](#__codelineno-8-4)[](#__codelineno-8-5)df = pl.DataFrame({"person": ["Alice", "Bob", "Charlie"], "age": [20, 30, 40]}) [](#__codelineno-8-6)transformed_df = mo.ui.dataframe(df) [](#__codelineno-8-7)transformed_df` `[](#__codelineno-9-1)# Cell 2 [](#__codelineno-9-2)# transformed_df.value holds the transformed dataframe [](#__codelineno-9-3)transformed_df.value` ### Formatting values[¶](#formatting-values "Permanent link") Use `format_mapping` to format values for display in the dataframe UI. This affects how values appear in the table but does not change the underlying data returned by `.value` or downloads. `[](#__codelineno-11-1)import marimo as mo [](#__codelineno-11-2)import pandas as pd [](#__codelineno-11-3)[](#__codelineno-11-4)df = pd.DataFrame( [](#__codelineno-11-5) {"person": ["Alice", "Bob"], "age": [20, 30], "height_cm": [165.2, 180.4]} [](#__codelineno-11-6)) [](#__codelineno-11-7)[](#__codelineno-11-8)def format_height(value: float) -> str: [](#__codelineno-11-9) return f"{value:.1f} cm" [](#__codelineno-11-10)[](#__codelineno-11-11)mo.ui.dataframe( [](#__codelineno-11-12) df, [](#__codelineno-11-13) format_mapping={ [](#__codelineno-11-14) "age": "{:d} years".format, [](#__codelineno-11-15) "height_cm": format_height, [](#__codelineno-11-16) }, [](#__codelineno-11-17))` ### Custom filters[¶](#custom-filters "Permanent link") Create custom filters with marimo UI elements, like sliders and dropdowns. pandaspolarslive example `[](#__codelineno-12-1)# Cell 1 - create a dataframe [](#__codelineno-12-2)df = pd.DataFrame({"person": ["Alice", "Bob", "Charlie"], "age": [20, 30, 40]})` `[](#__codelineno-13-1)# Cell 2 - create a filter [](#__codelineno-13-2)age_filter = mo.ui.slider(start=0, stop=100, value=50, label="Max age") [](#__codelineno-13-3)age_filter` `[](#__codelineno-14-1)# Cell 3 - display the transformed dataframe [](#__codelineno-14-2)filtered_df = df[df["age"] < age_filter.value] [](#__codelineno-14-3)mo.ui.table(filtered_df)` `[](#__codelineno-15-1)# Cell 1 [](#__codelineno-15-2)import marimo as mo [](#__codelineno-15-3)import polars as pl [](#__codelineno-15-4)[](#__codelineno-15-5)df = pl.DataFrame({ [](#__codelineno-15-6) "name": ["Alice", "Bob", "Charlie", "David"], [](#__codelineno-15-7) "age": [25, 30, 35, 40], [](#__codelineno-15-8) "city": ["New York", "London", "Paris", "Tokyo"] [](#__codelineno-15-9)}) [](#__codelineno-15-10)[](#__codelineno-15-11)age_filter = mo.ui.slider.from_series(df["age"], label="Max age") [](#__codelineno-15-12)city_filter = mo.ui.dropdown.from_series(df["city"], label="City") [](#__codelineno-15-13)[](#__codelineno-15-14)mo.hstack([age_filter, city_filter])` `[](#__codelineno-16-1)# Cell 2 [](#__codelineno-16-2)filtered_df = df.filter((pl.col("age") <= age_filter.value) & (pl.col("city") == city_filter.value)) [](#__codelineno-16-3)mo.ui.table(filtered_df)` Select dataframe rows[¶](#selecting-dataframes "Permanent link") ---------------------------------------------------------------- Display dataframes as interactive, [selectable charts](https://docs.marimo.io/guides/working_with_data/plotting/) using [`mo.ui.altair_chart`](https://docs.marimo.io/api/plotting/#marimo.ui.altair_chart " marimo.ui.altair_chart") or [`mo.ui.plotly`](https://docs.marimo.io/api/plotting/#marimo.ui.plotly " marimo.ui.plotly"), or as a row-selectable table with [`mo.ui.table`](https://docs.marimo.io/api/inputs/table/#marimo.ui.table " marimo.ui.table"). Select points in the chart, or select a table row, and your selection is _automatically sent to Python as a subset of the original dataframe_. Select rows in a table, get them back as a dataframe pandaspolarslive example `[](#__codelineno-18-1)# Cell 1 - display a dataframe [](#__codelineno-18-2)import marimo as mo [](#__codelineno-18-3)import pandas as pd [](#__codelineno-18-4)[](#__codelineno-18-5)df = pd.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]}) [](#__codelineno-18-6)table = mo.ui.table(df, selection="multi") [](#__codelineno-18-7)table` `[](#__codelineno-19-1)# Cell 2 - display the selection [](#__codelineno-19-2)table.value` `[](#__codelineno-20-1)# Cell 1 - display a dataframe [](#__codelineno-20-2)import marimo as mo [](#__codelineno-20-3)import polars as pl [](#__codelineno-20-4)[](#__codelineno-20-5)df = pl.DataFrame({"a": [1, 2, 3], "b": [4, 5, 6]}) [](#__codelineno-20-6)table = mo.ui.table(df, selection="multi") [](#__codelineno-20-7)table` `[](#__codelineno-21-1)# Cell 2 - display the selection [](#__codelineno-21-2)table.value` Dataframe panels[¶](#dataframe-panels "Permanent link") ------------------------------------------------------- Dataframe outputs in marimo come with several panels to help you visualize, explore, and page through your data interactively. These panels are accessible via toggles at the bottom-left of a dataframe output. If you need further control, after opening a panel you can * **pin the panel** to the side of your editor for persistent access; * **toggle focus** to automatically display the currently focused dataframe in the panel. Note Toggles are visible when editing notebooks (with `marimo edit ...`) but not when running notebooks as apps (with `marimo run ...`), except for the row viewer which is available in both. ### Row viewer panel[¶](#row-viewer-panel "Permanent link") To inspect individual rows, open the **row viewer**. This presents a vertical view of the selected row. * **Press `Space`** to select/deselect the current row * **Use arrow keys** (`←` `→`) to navigate between rows * **Click** on any row in the dataframe to view its data in the panel ### Column explorer panel[¶](#column-explorer-panel "Permanent link") To explore your data, open the **column explorer** where you can find summary statistics and charts for each column. Click the `+` button to add the chart code to a new cell. This requires the `altair` package to be installed. For large dataframes, `vegafusion` is also needed to render charts. To use the generated Python code, enable vegafusion in your notebook: `[](#__codelineno-23-1)import altair [](#__codelineno-23-2)[](#__codelineno-23-3)altair.data_transformers.enable("vegafusion")` ### Chart builder[¶](#chart-builder "Permanent link") The chart builder toggle lets you rapidly develop charts using a GUI, while also generating Python code to insert in your notebook. Refer to the [chart builder guide](https://docs.marimo.io/guides/working_with_data/plotting/#chart-builder) for more details. Preferences[¶](#preferences "Permanent link") --------------------------------------------- When you run a SQL cell in marimo, you can get the output returned as a dataframe. If you have a preference for a specific dataframe library as a default you can configure the "default SQL output" in the user settings by going to the "Runtime" tab. Configure the default SQL output Alternatively you can also use the [marimo configuration file](https://docs.marimo.io/guides/configuration/#user-configuration) to configure the default SQL output. `[](#__codelineno-24-1)[runtime] [](#__codelineno-24-2)default_sql_output = "native"` Example notebook[¶](#example-notebook "Permanent link") ------------------------------------------------------- For a comprehensive example of using Polars with marimo, check out our [Polars example notebook](https://github.com/marimo-team/marimo/blob/main/examples/third_party/polars/polars_example.py). Run it with: `[](#__codelineno-25-1)marimo edit https://raw.githubusercontent.com/marimo-team/marimo/main/examples/third_party/polars/polars_example.py` Plotting - marimo https://docs.marimo.io/guides/working_with_data/plotting/ marimo supports most major plotting libraries, including Matplotlib, Seaborn, Plotly, Altair, and HoloViews. Just import your plotting library of choice and use it as you normally would. For matplotlib, Altair, and Plotly plots, marimo does something special: wrap your plot in [`mo.ui.matplotlib`](https://docs.marimo.io/api/plotting/#marimo.ui.matplotlib " marimo.ui.matplotlib"), [`mo.ui.altair_chart`](https://docs.marimo.io/api/plotting/#marimo.ui.altair_chart " marimo.ui.altair_chart") or [`mo.ui.plotly`](https://docs.marimo.io/api/plotting/#marimo.ui.plotly " marimo.ui.plotly"), then select and filter with your mouse — marimo automatically sends the selected data back to Python! > For a video overview of reactive plots, check out our [YouTube tutorial](https://youtu.be/KFXsm1wr408). Reactive plots! ⚡[¶](#reactive-plots "Permanent link") ------------------------------------------------------ Requirements Reactive plots currently require matplotlib, Altair, or Plotly. Matplotlib supports box and lasso selections (best suited for scatter plots); selections in Plotly are limited to scatter/scattergl plots, bar charts, histograms, heatmaps, treemaps, and sunburst charts; Altair supports a larger class of plots for selections. ### matplotlib[¶](#matplotlib "Permanent link") Use [`mo.ui.matplotlib`](https://docs.marimo.io/api/plotting/#marimo.ui.matplotlib " marimo.ui.matplotlib") to make matplotlib plots **reactive**: select data on the frontend, then use the selection to filter your data in Python. Two selection modes are supported: * **Box selection** — click and drag to draw a rectangular region. * **Lasso selection** — hold Shift and drag to draw a freehand polygon. After selecting, use `fig.value.get_mask(x, y)` to get a boolean mask of the points inside the selection. When nothing is selected, `fig.value` is falsy and `get_mask()` returns an all-`False` array. #### Example[¶](#example "Permanent link") codelive example `[](#__codelineno-0-1)import matplotlib.pyplot as plt [](#__codelineno-0-2)import marimo as mo [](#__codelineno-0-3)import numpy as np [](#__codelineno-0-4)[](#__codelineno-0-5)x = np.random.randn(500) [](#__codelineno-0-6)y = np.random.randn(500) [](#__codelineno-0-7)plt.scatter(x, y) [](#__codelineno-0-8)# Wrap the Axes in mo.ui.matplotlib to make them reactive ⚡ [](#__codelineno-0-9)ax = mo.ui.matplotlib(plt.gca()) [](#__codelineno-0-10)ax` `[](#__codelineno-1-1)# In another cell — filter your data using the selection [](#__codelineno-1-2)mask = ax.value.get_mask(x, y) [](#__codelineno-1-3)selected_x, selected_y = x[mask], y[mask]` #### Debouncing[¶](#debouncing "Permanent link") By default, the selection streams to Python as you drag. For expensive downstream computations or very large datasets, pass `debounce=True` so the value is only sent on mouse-up: `[](#__codelineno-3-1)ax = mo.ui.matplotlib(plt.gca(), debounce=True)` #### Selection types[¶](#selection-types "Permanent link") `ax.value` is one of three types: | Type | When | Attributes | | --- | --- | --- | | `EmptySelection` | Nothing selected (falsy) | — | | `BoxSelection` | Box drag | `x_min`, `x_max`, `y_min`, `y_max` | | `LassoSelection` | Shift+drag | `vertices` (tuple of `(x, y)` pairs) | All three have a `get_mask(x, y)` method that returns a boolean NumPy array, so you can always write: `[](#__codelineno-4-1)mask = ax.value.get_mask(x, y)` ### Altair[¶](#altair "Permanent link") Use [`mo.ui.altair_chart`](https://docs.marimo.io/api/plotting/#marimo.ui.altair_chart " marimo.ui.altair_chart") to easily create interactive, selectable plots: _selections you make on the frontend are automatically made available as Pandas dataframes in Python._ Wrap an Altair chart in [`mo.ui.altair_chart`](https://docs.marimo.io/api/plotting/#marimo.ui.altair_chart " marimo.ui.altair_chart") to make it **reactive**: select data on the frontend, access it via the chart's `value` attribute (`chart.value`). #### Disabling automatic selection[¶](#disabling-automatic-selection "Permanent link") marimo automatically adds a default selection based on the mark type, however, you may want to customize the selection behavior of your Altair chart. You can do this by setting `chart_selection` and `legend_selection` to `False`, and using `.add_params` directly on your Altair chart. `[](#__codelineno-6-1)# Create an interval selection [](#__codelineno-6-2)brush = alt.selection_interval(encodings=["x"]) [](#__codelineno-6-3)[](#__codelineno-6-4)_chart = ( [](#__codelineno-6-5) alt.Chart(traces, height=150) [](#__codelineno-6-6) .mark_line() [](#__codelineno-6-7) .encode(x="index:Q", y="value:Q", color="traces:N") [](#__codelineno-6-8) .add_params(brush) # add the selection to the chart [](#__codelineno-6-9)) [](#__codelineno-6-10)[](#__codelineno-6-11)chart = mo.ui.altair_chart( [](#__codelineno-6-12) _chart, [](#__codelineno-6-13) # disable automatic selection [](#__codelineno-6-14) chart_selection=False, [](#__codelineno-6-15) legend_selection=False [](#__codelineno-6-16)) [](#__codelineno-6-17)chart # You can now access chart.value to get the selected data` _Reactive plots are just one way that marimo **makes your data tangible**._ #### Example[¶](#example_1 "Permanent link") `[](#__codelineno-7-1)import marimo as mo [](#__codelineno-7-2)import altair as alt [](#__codelineno-7-3)import vega_datasets [](#__codelineno-7-4)[](#__codelineno-7-5)# Load some data [](#__codelineno-7-6)cars = vega_datasets.data.cars() [](#__codelineno-7-7)[](#__codelineno-7-8)# Create an Altair chart [](#__codelineno-7-9)chart = alt.Chart(cars).mark_point().encode( [](#__codelineno-7-10) x='Horsepower', # Encoding along the x-axis [](#__codelineno-7-11) y='Miles_per_Gallon', # Encoding along the y-axis [](#__codelineno-7-12) color='Origin', # Category encoding by color [](#__codelineno-7-13)) [](#__codelineno-7-14)[](#__codelineno-7-15)# Make it reactive ⚡ [](#__codelineno-7-16)chart = mo.ui.altair_chart(chart)` `[](#__codelineno-8-1)# In a new cell, display the chart and its data filtered by the selection [](#__codelineno-8-2)mo.vstack([chart, chart.value.head()])` #### Learning Altair[¶](#learning-altair "Permanent link") If you're new to **Altair**, we highly recommend exploring the [Altair documentation](https://altair-viz.github.io/). Altair provides a declarative, concise, and simple way to create highly interactive and sophisticated plots. Altair is based on [Vega-Lite](https://vega.github.io/vega-lite/), an exceptional tool for creating interactive charts that serves as the backbone for marimo's reactive charting capabilities. ##### Concepts[¶](#concepts "Permanent link") Learn by doing? Skip this section! This section summarizes the main concepts used by Altair (and Vega-Lite). Feel free to skip this section and return later. Our choice to use the Vega-Lite specification was driven by its robust data model, which is well-suited for data analysis. Some key concepts are summarized below. (For a more detailed explanation, with examples, we recommend the [Basic Statistical Visualization](https://altair-viz.github.io/getting_started/starting.html) tutorial from Altair.) * **Data Source**: This is the information that will be visualized in the chart. It can be provided in various formats such as a dataframe, a list of dictionaries, or a URL pointing to the data source. * **Mark Type**: This refers to the visual representation used for each data point on the chart. The options include 'bar', 'dot', 'circle', 'area', and 'line'. Each mark type offers a different way to visualize and interpret the data. * **Encoding**: This is the process of mapping various aspects or dimensions of the data to visual characteristics of the marks. Encodings can be of different types: * **Positional Encodings**: These are encodings like 'x' and 'y' that determine the position of the marks in the chart. * **Categorical Encodings**: These are encodings like 'color' and 'shape' that categorize data points. They are typically represented in a legend for easy reference. * **Transformations**: These are operations that can be applied to the data before it is visualized, for example, filtering and aggregation. These transformations allow for more complex and nuanced visualizations. **Automatically interactive.** marimo adds interactivity automatically, based on the mark used and the encodings. For example, if you use a `mark_point` and an `x` encoding, marimo will automatically add a brush selection to the chart. If you add a `color` encoding, marimo will add a legend and a click selection. #### Automatic Selections[¶](#automatic-selections "Permanent link") By default [`mo.ui.altair_chart`](https://docs.marimo.io/api/plotting/#marimo.ui.altair_chart " marimo.ui.altair_chart") will make the chart and legend selectable. Depending on the mark type, the chart will either have a `point` or `interval` ("brush") selection. When using non-positional encodings (color, size, etc), [`mo.ui.altair_chart`](https://docs.marimo.io/api/plotting/#marimo.ui.altair_chart " marimo.ui.altair_chart") will also make the legend selectable. Selection configurable through `*_selection` params in [`mo.ui.altair_chart`](https://docs.marimo.io/api/plotting/#marimo.ui.altair_chart " marimo.ui.altair_chart"). See the [API docs](https://docs.marimo.io/api/plotting/#marimo.ui.altair_chart " marimo.ui.altair_chart") for details. Note You may still add your own selection parameters via Altair or Vega-Lite. marimo will not override your selections. #### Altair transformations[¶](#altair-transformations "Permanent link") Altair supports a variety of transformations, such as filtering, aggregation, and sorting. These transformations can be used to create more complex and nuanced visualizations. For example, you can use a filter to show only the points that meet a certain condition, or use an aggregation to show the average value of a variable. In order for marimo's reactive plots to work with transformations, you must install `vegafusion`, as this feature uses `chart.transformed_data` (which requires version 1.4.0 or greater of the `vegafusion` packages). `[](#__codelineno-9-1)# These can be installed with pip using: [](#__codelineno-9-2)pip install "vegafusion[embed]>=1.4.0" [](#__codelineno-9-3)# Or with conda using: [](#__codelineno-9-4)conda install -c conda-forge "vegafusion-python-embed>=1.4.0" "vegafusion>=1.4.0"` ### Plotly[¶](#plotly "Permanent link") Supported charts marimo can render any Plotly plot, but [`mo.ui.plotly`](https://docs.marimo.io/api/plotting/#marimo.ui.plotly " marimo.ui.plotly") only supports reactive selections for scatter/scattergl plots, bar charts, histograms, heatmaps, treemaps, and sunburst charts. If you require other kinds of selection, please [file an issue](https://github.com/marimo-team/marimo/issues). Use [`mo.ui.plotly`](https://docs.marimo.io/api/plotting/#marimo.ui.plotly " marimo.ui.plotly") to create selectable Plotly plots whose values are sent back to Python on selection. matplotlib[¶](#matplotlib_1 "Permanent link") --------------------------------------------- To output a matplotlib plot in a cell's output area, include its `Axes` or `Figure` object as the last expression in your notebook. For example: ``[](#__codelineno-11-1)plt.plot([1, 2]) [](#__codelineno-11-2)# plt.gca() gets the current `Axes` [](#__codelineno-11-3)plt.gca()`` or `[](#__codelineno-12-1)fig, ax = plt.subplots() [](#__codelineno-12-2)[](#__codelineno-12-3)ax.plot([1, 2]) [](#__codelineno-12-4)ax` If you want to output the plot in the console area, use `plt.show()` or `fig.show()`. ### Interactive plots with pan and zoom[¶](#interactive-plots-with-pan-and-zoom "Permanent link") To make matplotlib plots interactive with pan and zoom, use [mo.mpl.interactive](https://docs.marimo.io/api/plotting/#marimo.mpl.interactive " marimo.mpl.interactive"). This does not support reactive selection. Chart builder[¶](#chart-builder "Permanent link") ------------------------------------------------- marimo comes with a built-in chart builder that makes it easy to create plots specialized to your dataframes with just a few clicks. As you make your charts, marimo generates Python code that you can add to your notebook to save them. You can toggle the chart builder with a button at the bottom-left of a dataframe output. This provides a GUI interface to create many kinds of plots, while also generating Python code. Charts are powered by [Vega-Lite](https://vega.github.io/vega-lite/). To save a chart, click the `+` button in the `Python code` tab to add the code to a new cell. Note This feature is in active development. Please report any issues or feedback [here](https://github.com/marimo-team/marimo/issues). SQL - marimo https://docs.marimo.io/guides/working_with_data/sql/ Using SQL[¶](#using-sql "Permanent link") ----------------------------------------- marimo lets you mix and match **Python and SQL**: Use SQL to query Python dataframes (or databases like SQLite and Postgres), and get the query result back as a Python dataframe. > For a video overview on how to use SQL in marimo, watch our [YouTube tutorial](https://youtu.be/IHEf5HwU7R0). To create a SQL cell, you first need to install additional dependencies, including [duckdb](https://duckdb.org/): install with pipinstall with uvinstall with conda `[](#__codelineno-0-1)pip install "marimo[sql]"` `[](#__codelineno-2-1)conda install -c conda-forge marimo duckdb polars` Example[¶](#example "Permanent link") ------------------------------------- In this example notebook, we have a Pandas dataframe and a SQL cell that queries it. Notice that the query result is returned as a Python dataframe and usable in subsequent cells. Creating SQL cells[¶](#creating-sql-cells "Permanent link") ----------------------------------------------------------- You can create SQL cells in one of three ways: 1. **Right-click** an "add cell" button ("+" icon) next to a cell and choose "SQL cell" 2. Convert a empty cell to SQL via the cell context menu 3. Click the SQL button that appears at the bottom of the notebook Add SQL Cell This creates a "**SQL**" cell for you, which is syntactic sugar for Python code. The underlying code looks like: `[](#__codelineno-3-1)output_df = mo.sql(f"SELECT * FROM my_table LIMIT {max_rows.value}")` Notice that we have an **`output_df`** variable in the cell. This contains the query result, and is a Polars DataFrame (if you have `polars` installed) or a Pandas DataFrame (if you don't). One of them must be installed in order to interact with the query result. The SQL statement itself is an f-string, letting you interpolate Python values into the query with `{}`. In particular, this means your SQL queries can depend on the values of UI elements or other Python values, and they are fit into marimo's reactive dataflow graph. SQL Output Types[¶](#sql-output-types "Permanent link") ------------------------------------------------------- marimo supports different output types for SQL queries, which is particularly useful when working with large datasets. You can configure this in your application configuration in the top right of the marimo editor. The available options are: * `native`: Uses DuckDB's native lazy relation (recommended for best performance) * `lazy-polars`: Returns a lazy Polars DataFrame * `pandas`: Returns a Pandas DataFrame * `polars`: Returns an eager Polars DataFrame * `auto`: Automatically chooses based on installed packages (first tries `polars` then `pandas`) For best performance with large datasets, we recommend using `native` to avoid loading the entire result set into memory and to more easily chain SQL cells together. By default, only the first 10 rows are displayed in the UI to prevent memory issues. Set a default The default output type is currently `auto`, but we recommend explicitly setting the output type to `native` for best performance with large datasets or `polars` if you need to work with the results in Python code. You can configure this in your application settings. Reference a local dataframe[¶](#reference-a-local-dataframe "Permanent link") ----------------------------------------------------------------------------- You can reference a local dataframe in your SQL cell by using the name of the Python variable that holds the dataframe. If you have a database connection with a table of the same name, the database table will be used instead. Reference a dataframe Since the output dataframe variable (`_df`) has an underscore, making it private, it is not referenceable from other cells. Reference the output of a SQL cell[¶](#reference-the-output-of-a-sql-cell "Permanent link") ------------------------------------------------------------------------------------------- Defining a non-private (non-underscored) output variable in the SQL cell allows you to reference the resulting dataframe in other Python and SQL cells. Reference the SQL result Querying files, databases, and APIs[¶](#querying-files-databases-and-apis "Permanent link") ------------------------------------------------------------------------------------------- In the above example, you may have noticed we queried an HTTP endpoint instead of a local dataframe. We are not only limited to querying local dataframes; we can also query files, databases such as Postgres and SQLite, and APIs: `[](#__codelineno-4-1)-- or [](#__codelineno-4-2)SELECT * FROM 's3://my-bucket/file.parquet'; [](#__codelineno-4-3)-- or [](#__codelineno-4-4)SELECT * FROM read_csv('path/to/example.csv'); [](#__codelineno-4-5)-- or [](#__codelineno-4-6)SELECT * FROM read_parquet('path/to/example.parquet');` For a full list you can check out the [duckdb extensions](https://duckdb.org/docs/extensions/overview). You can also check out our [examples on GitHub](https://github.com/marimo-team/marimo/tree/main/examples/sql). Escaping SQL brackets[¶](#escaping-sql-brackets "Permanent link") ----------------------------------------------------------------- Our "SQL" cells are really just Python under the hood to keep notebooks as pure Python scripts. By default, we use `f-strings` for SQL strings, which allows for parameterized SQL like `SELECT * from table where value < {min}`. To escape real `{`/`}` that you don't want parameterized, use double `{{...}}`: `[](#__codelineno-5-1)SELECT unnest([{{'a': 42, 'b': 84}}, {{'a': 100, 'b': NULL}}]);` Connecting to a custom database[¶](#connecting-to-a-custom-database "Permanent link") ------------------------------------------------------------------------------------- There are two ways to connect to a database in marimo: ### 1\. Using the UI[¶](#1-using-the-ui "Permanent link") Click the "Add Database Connection" button in your notebook to connect to PostgreSQL, MySQL, SQLite, DuckDB, Snowflake, or BigQuery databases. The UI will guide you through entering your connection details securely. Environment variables picked up from your [`dotenv`](https://docs.marimo.io/guides/configuration/runtime_configuration/#environment-variables) can be used to fill out the database configuration fields. Add a database connection through the UI If you'd like to connect to a database that isn't supported by the UI, you can use the code method below, or submit a [feature request](https://github.com/marimo-team/marimo/issues/new?title=New%20database%20connection:&labels=enhancement&template=feature_request.yaml). ### 2\. Using Code[¶](#2-using-code "Permanent link") You can bring your own database via a **connection engine** with one of the following libraries * [SQLAlchemy](https://docs.sqlalchemy.org/en/20/core/connections.html#basic-usage) * [SQLModel](https://sqlmodel.tiangolo.com/tutorial/create-db-and-table/?h=create+engine#create-the-engine) * [Ibis](https://ibis-project.org/backends/athena) * [Custom DuckDB connection](https://duckdb.org/docs/api/python/overview.html#connection-options) * [ClickHouse Connect](https://clickhouse.com/docs/integrations/python#introduction) * [chDB](https://clickhouse.com/docs/chdb) By default, marimo uses the [in-memory duckdb connection](https://duckdb.org/docs/connect/overview.html#in-memory-database). List of supported databases Updated: 2025-04-30. This list is not exhaustive. | Database | Library | | --- | --- | | Amazon Athena | `sqlalchemy`, `sqlmodel`, `ibis` | | Amazon Redshift | `sqlalchemy`, `sqlmodel` | | Apache Drill | `sqlalchemy`, `sqlmodel` | | Apache Druid | `sqlalchemy`, `sqlmodel`, `ibis` | | Apache Hive and Presto | `sqlalchemy`, `sqlmodel` | | Apache Solr | `sqlalchemy`, `sqlmodel` | | BigQuery | `sqlalchemy`, `sqlmodel`, `ibis` | | ClickHouse | `clickhouse_connect`, `chdb` | | CockroachDB | `sqlalchemy`, `sqlmodel` | | Databricks | `sqlalchemy`, `sqlmodel`, `ibis` | | dlt | `ibis` | | Datafusion | `ibis` | | DuckDB | `duckdb` | | EXASolution | `sqlalchemy`, `sqlmodel`, `ibis` | | Elasticsearch (readonly) | `sqlalchemy`, `sqlmodel` | | Firebolt | `sqlalchemy`, `sqlmodel` | | Flink | `ibis` | | Google Sheets | `sqlalchemy`, `sqlmodel` | | Impala | `sqlalchemy`, `sqlmodel`, `ibis` | | Microsoft Access | `sqlalchemy`, `sqlmodel` | | Microsoft SQL Server | `sqlalchemy`, `sqlmodel`, `ibis` | | MonetDB | `sqlalchemy`, `sqlmodel` | | MySQL | `sqlalchemy`, `sqlmodel`, `ibis` | | OpenGauss | `sqlalchemy`, `sqlmodel` | | Oracle | `sqlalchemy`, `sqlmodel`, `ibis` | | PostgreSQL | `sqlalchemy`, `sqlmodel`, `ibis` | | PySpark | `ibis` | | RisingWave | `ibis` | | SAP HANA | `sqlalchemy`, `sqlmodel` | | Snowflake | `sqlalchemy`, `sqlmodel`, `ibis` | | SQLite | `sqlalchemy`, `sqlmodel`, `ibis` | | Teradata Vantage | `sqlalchemy`, `sqlmodel` | | TimePlus | `sqlalchemy`, `sqlmodel` | | Trino | `sqlalchemy`, `sqlmodel`, `ibis` | Define the engine as a Python variable in a cell: SQLAlchemySQLModelIbisDuckDBClickHouse ConnectchDB `[](#__codelineno-6-1)import sqlalchemy [](#__codelineno-6-2)[](#__codelineno-6-3)# Create an in-memory SQLite database with SQLAlchemy [](#__codelineno-6-4)sqlite_engine = sqlalchemy.create_engine("sqlite:///:memory:")` `[](#__codelineno-7-1)import sqlmodel [](#__codelineno-7-2)[](#__codelineno-7-3)# Create an in-memory SQLite database with SQLModel [](#__codelineno-7-4)sqlite_engine = sqlmodel.create_engine("sqlite:///:memory:")` `[](#__codelineno-8-1)import ibis [](#__codelineno-8-2)[](#__codelineno-8-3)# Create an in-memory SQLite database with Ibis [](#__codelineno-8-4)sqlite_engine = ibis.connect("sqlite:///:memory:")` `[](#__codelineno-9-1)import duckdb [](#__codelineno-9-2)[](#__codelineno-9-3)# Create a DuckDB connection [](#__codelineno-9-4)duckdb_conn = duckdb.connect("file.db")` ClickHouse Connect enables remote connections to ClickHouse databases. Refer to [the official docs](https://clickhouse.com/docs/integrations/python#gather-your-connection-details) for more configuration options. `[](#__codelineno-10-1)import clickhouse_connect [](#__codelineno-10-2)[](#__codelineno-10-3)engine = clickhouse_connect.get_client(host="localhost", port=8123, username="default", password="password")` Warning chDB is still new. You may experience issues with your queries. We recommend only using one connection at a time. Refer to [chDB docs](https://github.com/orgs/chdb-io/discussions/295) for more information. `[](#__codelineno-11-1)import chdb [](#__codelineno-11-2)[](#__codelineno-11-3)connection = chdb.connect(":memory:") [](#__codelineno-11-4)[](#__codelineno-11-5)# Supported formats with examples: [](#__codelineno-11-6)":memory:" # In-memory database [](#__codelineno-11-7)"test.db" # Relative path [](#__codelineno-11-8)"file:test.db" # Explicit file protocol [](#__codelineno-11-9)"/path/to/test.db" # Absolute path [](#__codelineno-11-10)"file:/path/to/test.db" # Absolute path with protocol [](#__codelineno-11-11)"file:test.db?param1=value1¶m2=value2" # With query parameters [](#__codelineno-11-12)"file::memory:?verbose&log-level=test" # In-memory with parameters [](#__codelineno-11-13)"///path/to/test.db?param1=value1" # Triple slash absolute path` marimo will auto-discover the engine and let you select it in the SQL cell's connection dropdown. Choose a custom database connection Database, schema, and table auto-discovery[¶](#database-schema-and-table-auto-discovery "Permanent link") --------------------------------------------------------------------------------------------------------- marimo will automatically discover the database connection and display the database, schemas, tables, and columns in the Data Sources panel. This panels lets you quickly navigate your database schema and reference tables and columns to pull in your SQL queries. Data Sources panel Note By default, marimo auto-discovers databases and schemas, but not tables and columns (to avoid performance issues with large databases). You can configure this behavior in your `pyproject.toml` file. Options are `true`, `false`, or `"auto"`. `"auto"` will determine whether to auto-discover based on the type of database (e.g. when the value is `"auto"`, Snowflake and BigQuery will not auto-discover tables and columns while SQLite, Postgres, and MySQL will): pyproject.toml `[](#__codelineno-12-1)[tool.marimo.datasources] [](#__codelineno-12-2)auto_discover_schemas = true # Default: true [](#__codelineno-12-3)auto_discover_tables = "auto" # Default: "auto" [](#__codelineno-12-4)auto_discover_columns = "auto" # Default: false` Catalogs[¶](#catalogs "Permanent link") --------------------------------------- marimo supports connecting to Iceberg catalogs. You can click the "+" button in the Datasources panel or manually create a [PyIceberg](https://py.iceberg.apache.org/) `Catalog` connection. PyIceberg supports a variety of catalog implementations including REST, SQL, Glue, DynamoDB, and more. `[](#__codelineno-13-1)from pyiceberg.catalog.rest import RestCatalog [](#__codelineno-13-2)[](#__codelineno-13-3)catalog = RestCatalog( [](#__codelineno-13-4) name="catalog", [](#__codelineno-13-5) warehouse="1234567890", [](#__codelineno-13-6) uri="https://my-catalog.com", [](#__codelineno-13-7) token="my-token", [](#__codelineno-13-8))` Catalogs will appear in the Datasources panel, but they cannot be used as an engine in SQL cells. However, you can still load the table and use it in subsequent Python or SQL cells. `[](#__codelineno-14-1)df = catalog.load_table(("my-namespace", "my-table")).to_polars()` Utilities[¶](#utilities "Permanent link") ----------------------------------------- marimo provides a few utilities when working with SQL **SQL Linter** Lint your SQL code and provide better autocompletions and error highlighting. To disable the linter, you can set the `sql_linter` configuration to `false` in your `pyproject.toml` file or disable it in the marimo editor's settings menu. **SQL Formatting** Click on the paint roller icon at the bottom right of the SQL cell to format your SQL code. **SQL Mode** For In-Memory DuckDB, marimo offers a Validate mode that will validate your SQL as you write it. Under the hood, this runs a debounced query in EXPLAIN mode and returns the parsed errors. Interactive tutorial[¶](#interactive-tutorial "Permanent link") --------------------------------------------------------------- For an interactive tutorial, run at your command-line. Examples[¶](#examples "Permanent link") --------------------------------------- Check out our [examples on GitHub](https://github.com/marimo-team/marimo/tree/main/examples/sql). Remote Storage - marimo https://docs.marimo.io/guides/working_with_data/remote_storage/ marimo makes it easy to work with cloud storage and remote filesystems by automatically detecting [obstore](https://developmentseed.org/obstore/) and [fsspec](https://filesystem-spec.readthedocs.io/) storage connections in your notebook. From the Files panel, you can browse directories, search entries, copy URLs, and download files—all without leaving the editor. Supported libraries[¶](#supported-libraries "Permanent link") ------------------------------------------------------------- marimo auto-discovers variables that are instances of: | Library | Base class | Example stores | | --- | --- | --- | | [obstore](https://developmentseed.org/obstore/) | `obstore.store.ObjectStore` | `S3Store`, `GCSStore`, `AzureStore`, `HTTPStore`, `LocalStore`, `MemoryStore` | | [fsspec](https://filesystem-spec.readthedocs.io/) | `fsspec.AbstractFileSystem` | `S3FileSystem`, `GithubFileSystem`, `FTPFileSystem`, `DatabricksFileSystem`, and [many more](https://filesystem-spec.readthedocs.io/en/latest/api.html#built-in-implementations) | Creating a storage connection[¶](#creating-a-storage-connection "Permanent link") --------------------------------------------------------------------------------- You can either create a storage connection using the UI or code. ### 1\. Using the UI[¶](#1-using-the-ui "Permanent link") From the Files panel in the sidebar, expand the **Remote Storage** section and click the **Add remote storage** button. The UI will guide you through entering your storage connection details. If you'd like to connect to a storage that isn't supported by the UI, you can use the code method below, or submit a [feature request](https://github.com/marimo-team/marimo/issues/new?title=Add%20new%20storage%20connection%20UI:&labels=enhancement&template=feature_request.yaml). ### 2\. Using code[¶](#2-using-code "Permanent link") #### obstore[¶](#obstore "Permanent link") `[](#__codelineno-0-1)from obstore.store import S3Store [](#__codelineno-0-2)[](#__codelineno-0-3)store = S3Store.from_url( [](#__codelineno-0-4) "s3://my-bucket", [](#__codelineno-0-5) access_key_id="...", [](#__codelineno-0-6) secret_access_key="...", [](#__codelineno-0-7))` #### fsspec[¶](#fsspec "Permanent link") `[](#__codelineno-1-1)from fsspec.implementations.github import GithubFileSystem [](#__codelineno-1-2)[](#__codelineno-1-3)repo = GithubFileSystem(org="marimo-team", repo="marimo")` After the cell runs, the **Remote Storage** section will populate with your connection, its detected protocol, and root path. Multiple connections[¶](#multiple-connections "Permanent link") --------------------------------------------------------------- You can have multiple storage connections in the same notebook — each one appears as a separate namespace. The panel header shows the variable name so you can tell them apart. `[](#__codelineno-2-1)from obstore.store import S3Store [](#__codelineno-2-2)[](#__codelineno-2-3)prod = S3Store.from_url("s3://prod-bucket") [](#__codelineno-2-4)staging = S3Store.from_url("s3://staging-bucket")` Understanding errors - marimo https://docs.marimo.io/guides/understanding_errors/ marimo imposes a few constraints on your notebook code: * no multiply defined variables: each variable can be defined in only one cell * no cycles: if one cell declares variable `a` and reads `b`, then another cannot declare `b` and read `a`. * no `import *`: importing all symbols from a library is not allowed Why these constraints? These constraints let marimo work its magic, making your notebooks: * **reproducible**, with a well-defined execution order, no hidden state, and no hidden bugs; * **executable** as a script; * **interactive** with UI elements that work without callbacks; * **shareable as a web app**, with far better performance than streamlit. As a bonus, you'll find that you end up with cleaner, reusable code. When a cell violates any of these constraints, marimo doesn't run it and instead reports an error. In these guides, we explain these errors and provide tips for how to work around them. These errors might be surprising at first, but spend just a bit of time with marimo and adhering to these constraints will become second nature — and you'll get used to writing error-free code by default. Lint Rules[¶](#lint-rules "Permanent link") ------------------------------------------- marimo includes a comprehensive linting system that automatically detects these constraints and other code quality issues. The linter can help you identify and fix problems before they cause runtime errors. Run the linter using: See the [Lint Rules](https://docs.marimo.io/guides/lint_rules/) guide for a complete list of rules and detailed explanations. | Guide | Description | | --- | --- | | [Multiple definitions](https://docs.marimo.io/guides/understanding_errors/multiple_definitions/) | How to deal with variables defined in multiple cells | | [Import `*`](https://docs.marimo.io/guides/understanding_errors/import_star/) | Why you can't use `import *` | | [Cycles](https://docs.marimo.io/guides/understanding_errors/cycles/) | How to resolve cycle errors | | [setup](https://docs.marimo.io/guides/understanding_errors/setup/) | How to enable top level definitions | Expensive notebooks - marimo https://docs.marimo.io/guides/expensive_notebooks/ Working with expensive notebooks[¶](#working-with-expensive-notebooks "Permanent link") --------------------------------------------------------------------------------------- marimo provides tools to control when cells run. Use these tools to prevent expensive cells, which may call APIs or take a long time to run, from accidentally running. Stop execution with `mo.stop`[¶](#stop-execution-with-mostop "Permanent link") ------------------------------------------------------------------------------ Use [`mo.stop`](https://docs.marimo.io/api/control_flow/#marimo.stop " marimo.stop") to stop a cell from executing if a condition is met: `[](#__codelineno-0-1)# if condition is True, the cell will stop executing after mo.stop() returns [](#__codelineno-0-2)mo.stop(condition) [](#__codelineno-0-3)# this won't be called if condition is True [](#__codelineno-0-4)expensive_function_call()` Use [`mo.stop`](https://docs.marimo.io/api/control_flow/#marimo.stop " marimo.stop") with [`mo.ui.run_button()`](https://docs.marimo.io/api/inputs/run_button/#marimo.ui.run_button " marimo.ui.run_button") to require a button press for expensive cells: Configure how marimo runs cells[¶](#configure-how-marimo-runs-cells "Permanent link") ------------------------------------------------------------------------------------- ### Disable cell autorun[¶](#disable-cell-autorun "Permanent link") If you habitually work with very expensive notebooks, you can [disable automatic execution](https://docs.marimo.io/guides/configuration/runtime_configuration/#on-cell-change-disabling-autorun-on-cell-change-lazy-execution). When automatic execution is disabled, when you run a cell, marimo marks dependent cells as stale instead of running them automatically. ### Disable autorun on startup[¶](#disable-autorun-on-startup "Permanent link") marimo autoruns notebooks on startup, with `marimo edit notebook.py` behaving analogously to `python notebook.py`. This can also be disabled through the [notebook settings](https://docs.marimo.io/guides/configuration/runtime_configuration/#on-startup). ### Disable individual cells[¶](#disable-individual-cells "Permanent link") marimo lets you temporarily disable cells from automatically running. This is helpful when you want to edit one part of a notebook without triggering execution of other parts. See the [reactivity guide](https://docs.marimo.io/guides/reactivity/#disabling-cells) for more info. Manage memory[¶](#manage-memory "Permanent link") ------------------------------------------------- Here are a few tips for managing the memory consumption of your notebooks, on host or GPU. ### Wrap intermediate computations in functions[¶](#wrap-intermediate-computations-in-functions "Permanent link") By default, global variables live in the kernel memory. Intermediate variables that are defined in functions are cleaned up automatically. For example, if `X` is a temporary: **Do this:** `[](#__codelineno-2-1)def _(): [](#__codelineno-2-2) X = torch.randn(1e4, 1e4, device='cuda') [](#__codelineno-2-3) Y = f(X) [](#__codelineno-2-4) return Y` **Don't do this:** `[](#__codelineno-3-1)X = torch.randn(1e4, 1e4, device='cuda') [](#__codelineno-3-2)Y = f(X) [](#__codelineno-3-3)# X still lives in program memory!` ### Use `del` to remove variables from kernel memory[¶](#use-del-to-remove-variables-from-kernel-memory "Permanent link") Use the `del` operator to remove variables from kernel memory. **In a single cell.** Prefer deleting variables in the cell they were defined in. For example, if `X` is a temporary that you don't need after computing `Y`: `[](#__codelineno-4-1)X = torch.randn(1e4, 1e4, device='cuda') [](#__codelineno-4-2)Y = f(X) [](#__codelineno-4-3)del X` **In another cell.** Sometimes, computations are spread across multiple cells, and you only realize later on that you need to free memory that you've already allocated. In such cases you can still use the `del` keyword. For example: `[](#__codelineno-5-1)data = load_large_dataset()` marimo inserts control dependences to make sure that variables are not deleted before they are used. When `del` is used to delete a variable that was defined in a another cell, the cell where `del` was used becomes a child of all other cells that reference that variable. In this case, that means marimo knows to run the third cell after the second cell, since the second cell references `data` and the third cell deletes it. However, once `data` is deleted, attempting to manually run the second cell will raise a `NameError`, and you'll need to re-run the defining cell in order to get your notebook back to a consistent state. Automatically snapshot outputs as HTML or IPYNB[¶](#automatically-snapshot-outputs-as-html-or-ipynb "Permanent link") --------------------------------------------------------------------------------------------------------------------- To keep a record of your cell outputs while working on your notebook, you can configure notebooks to automatically save as HTML or ipynb through the notebook menu (these files are saved in addition to the notebook's `.py` file). Snapshots are saved to a folder called `__marimo__` in the notebook directory. Learn more about exporting notebooks in our [exporting guide](https://docs.marimo.io/guides/exporting/). Cache expensive computations[¶](#cache-expensive-computations "Permanent link") ------------------------------------------------------------------------------- marimo provides two decorators to cache the return values of expensive functions: 1. In-memory caching with [`mo.cache`](https://docs.marimo.io/api/caching/#marimo.cache " marimo.cache") 2. Disk caching with [`mo.persistent_cache`](https://docs.marimo.io/api/caching/#marimo.persistent_cache " marimo.persistent_cache") Both utilities can be used as decorators or context managers. `mo.cache``mo.persistent_cache` `[](#__codelineno-8-1)import marimo as mo [](#__codelineno-8-2)[](#__codelineno-8-3)@mo.cache [](#__codelineno-8-4)def compute_embedding(data: str, embedding_dimension: int, model: str) -> np.ndarray: [](#__codelineno-8-5) ...` `[](#__codelineno-9-1)import marimo as mo [](#__codelineno-9-2)[](#__codelineno-9-3)@mo.persistent_cache [](#__codelineno-9-4)def compute_embedding(data: str, embedding_dimension: int, model: str) -> np.ndarray [](#__codelineno-9-5) ...` See our [guide on caching](https://docs.marimo.io/api/caching/) for details, including how the cache key is constructed, and limitations. Lazy-load expensive UIs[¶](#lazy-load-expensive-uis "Permanent link") --------------------------------------------------------------------- Lazily render UI elements that are expensive to compute using `marimo.lazy`. For example, `[](#__codelineno-10-1)import marimo as mo [](#__codelineno-10-2)[](#__codelineno-10-3)data = db.query("SELECT * FROM data") [](#__codelineno-10-4)mo.lazy(mo.ui.table(data))` In this example, `mo.ui.table(data)` will not be rendered on the frontend until is it in the viewport. For example, an element can be out of the viewport due to scroll, inside a tab that is not selected, or inside an accordion that is not open. However, in this example, data is eagerly computed, while only the rendering of the table is lazy. It is possible to lazily compute the data as well: see the next example. `[](#__codelineno-11-1)import marimo as mo [](#__codelineno-11-2)[](#__codelineno-11-3)def expensive_component(): [](#__codelineno-11-4) import time [](#__codelineno-11-5) time.sleep(1) [](#__codelineno-11-6) data = db.query("SELECT * FROM data") [](#__codelineno-11-7) return mo.ui.table(data) [](#__codelineno-11-8)[](#__codelineno-11-9)accordion = mo.accordion({ [](#__codelineno-11-10) "Charts": mo.lazy(expensive_component) [](#__codelineno-11-11)})` In this example, we pass a function to `mo.lazy` instead of a component. This function will only be called when the user opens the accordion. In this way, `expensive_component` lazily computed and we only query the database when the user needs to see the data. This can be useful when the data is expensive to compute and the user may not need to see it immediately. Migrate from Jupyter - marimo https://docs.marimo.io/guides/coming_from/jupyter/ Coming from Jupyter[¶](#coming-from-jupyter "Permanent link") ------------------------------------------------------------- If you're coming from Jupyter, here are a few tips to help you adapt to marimo notebooks. How marimo runs cells[¶](#how-marimo-runs-cells "Permanent link") ----------------------------------------------------------------- The biggest difference between marimo and Jupyter is the [execution model](https://docs.marimo.io/guides/reactivity/). A **Jupyter** notebook is a **REPL**: you execute blocks of code one at a time, and Jupyter has no understanding of how different blocks are related to each other. As a result a Jupyter notebook can easily accumulate **"hidden state"** (and hidden bugs) --- you might accidentally execute cells out of order, or you might run (or delete) a cell but forget to re-run cells that depended on its variables. Because of this, Jupyter notebooks suffer from a [reproducibility crisis](https://docs.marimo.io/faq/#faq-problems), with over a third of Jupyter notebooks on GitHub failing to reproduce. Unlike Jupyter, **marimo** notebooks understand how different blocks of code are related to each other, modeling your code as a graph on cells based on variable declarations and references. This eliminates hidden state, and it's also what enables marimo notebooks to be reused as apps and scripts. **By default, if you run a cell in marimo, all other cells that read its variables run automatically.** While this ensures that your code and outputs are in sync, it can take some time getting used to. **Here are some tips and tools to help you adapt to marimo's execution model.** ### Configure marimo's runtime[¶](#configure-marimos-runtime "Permanent link") [Configure marimo's runtime](https://docs.marimo.io/guides/configuration/runtime_configuration/) to not autorun on startup or on cell execution. Even when autorun is disabled, marimo still tracks dependencies across cells, marking dependents of a cell as stale when you run it. You can click a single button to run all your stale cells and bring your notebook back up-to-date. ### Stop execution with `mo.stop`[¶](#stop-execution-with-mostop "Permanent link") Use [`mo.stop`](https://docs.marimo.io/api/control_flow/#marimo.stop " marimo.stop") to stop a cell from executing if a condition is met: `[](#__codelineno-0-1)# if condition is True, the cell will stop executing after mo.stop() returns [](#__codelineno-0-2)mo.stop(condition) [](#__codelineno-0-3)# this won't be called if condition is True [](#__codelineno-0-4)expensive_function_call()` Use [`mo.stop()`](https://docs.marimo.io/api/control_flow/#marimo.stop " marimo.stop") in conjunction with [`mo.ui.run_button()`](https://docs.marimo.io/api/inputs/run_button/#marimo.ui.run_button " marimo.ui.run_button") to require a button press for expensive cells: ### Working with expensive notebooks[¶](#working-with-expensive-notebooks "Permanent link") For more tips on adapting to marimo's execution model, see our guide on [working with expensive notebooks](https://docs.marimo.io/guides/expensive_notebooks/). Redefining variables[¶](#redefining-variables "Permanent link") --------------------------------------------------------------- marimo "compiles" your notebook cells into a directed graph on cells, linked by variable declarations and references, reusing this graph to run your notebook as a script or app. For marimo's compilation to work, the same variable cannot be defined in multiple cells; otherwise, marimo wouldn't know what order to run cells in. To adapt to the restriction, we suggest: 1. Encapsulating code into functions when possible, to minimize the number of global variables. 2. Prefixing temporary variables with an underscore (`_my_temporary`), which makes the variable **local** to a cell. 3. Mutating variables in the cell that defines them. When working with **dataframes**, you might be used to redefining the same `df` variable in multiple cells. That won't work in marimo. Instead, try merging the cells into a single cell: _Don't_ do this: `[](#__codelineno-2-1)df = pd.DataFrame({"my_column": [1, 2]})` `[](#__codelineno-3-1)df["another_column"] = [3, 4]` _Instead_, do this: `[](#__codelineno-4-1)df = pd.DataFrame({"my_column": [1, 2]}) [](#__codelineno-4-2)df["another_column"] = [3, 4]` If you do need to transform a dataframe across multiple cells, you can alias the dataframe: `[](#__codelineno-5-1)df = pd.DataFrame({"my_column": [1, 2]})` `[](#__codelineno-6-1)augmented_df = df [](#__codelineno-6-2)augmented_df["another_column"] = [3, 4]` To learn how to write Pandas/Polars code in a functional style, which is more amenable to marimo's execution model, check out [this YouTube video](https://youtu.be/J0PJpdU7c4g). marimo's file format[¶](#marimos-file-format "Permanent link") -------------------------------------------------------------- marimo stores notebooks as Python, not JSON. This lets you version notebooks with git, [execute them as scripts](https://docs.marimo.io/guides/scripts/), and import named cells into other Python files. However, it does mean that your notebook outputs (e.g., plots) are not stored in the file. If you'd like to keep a visual record of your notebook work, [enable the "Auto-download as HTML/IPYNB" setting](https://docs.marimo.io/guides/configuration/), which will periodically snapshot your notebook as HTML or IPYNB to a `__marimo__` folder in the notebook directory. ### Converting Jupyter notebooks to marimo notebooks[¶](#converting-jupyter-notebooks-to-marimo-notebooks "Permanent link") Convert Jupyter notebooks to marimo notebooks at the command-line: `[](#__codelineno-7-1)marimo convert your_notebook.ipynb -o your_notebook.py` ### Converting Python scripts to marimo notebooks[¶](#converting-python-scripts-to-marimo-notebooks "Permanent link") marimo can also convert regular Python scripts to marimo notebooks: `[](#__codelineno-8-1)marimo convert your_script.py -o your_notebook.py` This supports: - **py:percent format**: If your script uses `# %%` cell markers, marimo will convert it to a multi-cell notebook (requires jupytext) - **Regular Python scripts**: Scripts without cell markers are converted to a single-cell notebook For py:percent conversion with uv: `[](#__codelineno-9-1)uvx --with=jupytext marimo convert your_script.py -o your_notebook.py` ### Exporting marimo notebooks to Jupyter notebooks[¶](#exporting-marimo-notebooks-to-jupyter-notebooks "Permanent link") Export to an `ipynb` file with `[](#__codelineno-10-1)marimo export ipynb notebook.py -o notebook.ipynb` Note that some marimo library functions, including UI elements, won't work in Jupyter notebooks. Magic commands[¶](#magic-commands "Permanent link") --------------------------------------------------- Because marimo notebooks are just Python (improving maintainability), marimo doesn't support IPython magic commands or `!`\-prefixed console commands. Here are some alternatives. ### Run console commands with subprocess.run[¶](#run-console-commands-with-subprocessrun "Permanent link") To run a console command, use Python's [subprocess.run](https://docs.python.org/3/library/subprocess.html#subprocess.run): `[](#__codelineno-11-1)import subprocess [](#__codelineno-11-2)[](#__codelineno-11-3)# run: "ls -l" [](#__codelineno-11-4)subprocess.run(["ls", "-l"])` ### Common magic commands replacements[¶](#common-magic-commands-replacements "Permanent link") | Magic Command | Replacement | | --- | --- | | %cd | `os.chdir()`, see also [`mo.notebook_dir()`](https://docs.marimo.io/api/miscellaneous/#marimo.notebook_dir " marimo.notebook_dir") | | %clear | Right-click or toggle the cell actions | | %debug | Python's built-in debugger: `breakpoint()` | | %env | `os.environ` | | %load | N/A - use Python imports | | %load\_ext | N/A | | %autoreload | marimo's [module autoreloader](https://docs.marimo.io/guides/editor_features/module_autoreloading/) | | %matplotlib | marimo auto-displays plots | | %pwd | `os.getcwd()` | | %pip | Use marimo's [built-in package management](https://docs.marimo.io/guides/editor_features/package_management/) | | %who\_ls | `dir()`, `globals()`, [`mo.refs()`](https://docs.marimo.io/api/miscellaneous/#marimo.refs " marimo.refs"), [`mo.defs()`](https://docs.marimo.io/api/miscellaneous/#marimo.defs " marimo.defs") | | %system | `subprocess.run()` | | %%time | `time.perf_counter()` or Python's timeit module | | %%timeit | Python's timeit module | | %%writefile | `with open("file.txt", "w") as f: f.write()` | | %%capture | [`mo.capture_stdout()`](https://docs.marimo.io/api/outputs/#marimo.capture_stdout " marimo.capture_stdout"), [`mo.capture_stderr()`](https://docs.marimo.io/api/outputs/#marimo.capture_stderr " marimo.capture_stderr") | | %%html | [`mo.Html()`](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass ") or [`mo.md()`](https://docs.marimo.io/api/markdown/#marimo.md " marimo.md") | | %%latex | [`mo.md(r'$$...$$')`](https://docs.marimo.io/api/markdown/#marimo.md " marimo.md") | ### Installing packages with marimo's package manager[¶](#installing-packages-with-marimos-package-manager "Permanent link") Use marimo's package management sidebar panel to install packages to your current environment. Learn more in our [package management guide](https://docs.marimo.io/guides/editor_features/package_management/). Interactive guide[¶](#interactive-guide "Permanent link") --------------------------------------------------------- This guide contains additional tips to help you adapt to marimo. Fun fact: the guide is itself a marimo notebook! Import star - marimo https://docs.marimo.io/guides/understanding_errors/import_star/ Star imports[¶](#star-imports "Permanent link") ----------------------------------------------- You're probably on this page because you just saw an error like this one: marimo raises this error you attempt to use `import *`. In this example, `x` was already defined, and the subsequent cell raised an error when we tried to run it. In your case, perhaps your variable is a loop variable (`i`), a dataframe (`df`), or a plot (`fig`, `ax`). Why can't I use `*` imports?[¶](#why-cant-i-use-imports "Permanent link") ------------------------------------------------------------------------- Star imports are incompatible with marimo's git-friendly file format and reproducible reactive execution: * marimo's Python file format stores code in functions, so notebooks can be imported as regular Python modules without executing all their code. But Python disallows `import *` everywhere except at the top-level of a module. * Star imports would also silently add names to globals, which would be incompatible with [reactive execution](https://docs.marimo.io/guides/reactivity/). Even Python's [official style guide](https://peps.python.org/pep-0008/) discourages the use of `import *`, writing: > Wildcard imports (from import \*) should be avoided, as they make it unclear which names are present in the namespace, confusing both readers and many automated tools. **What do I get in return?** By accepting this constraint on imports, marimo makes your notebooks: * **reproducible**, with a well-defined execution order, no hidden state, and no hidden bugs; * **executable** as a script; * **interactive** with UI elements that work without callbacks; * **shareable as a web app**, with far better performance than streamlit. As a bonus, you'll find that you end up with cleaner, reusable code. How do I fix this error?[¶](#how-do-i-fix-this-error "Permanent link") ---------------------------------------------------------------------- Fixing this error is simple: just import the module, and use `.` notation to access its members. instead of Multiple definitions - marimo https://docs.marimo.io/guides/understanding_errors/multiple_definitions/ You're probably on this page because you just saw an error like this one: marimo raises this error when a variable is defined in multiple cells. In this example, `x` was already defined, and the subsequent cell raised an error when we tried to run it. In your case, perhaps your variable is a loop variable (`i`), a dataframe (`df`), or a plot (`fig`, `ax`). Watch our YouTube explainer Why can't I redefine variables?[¶](#why-cant-i-redefine-variables "Permanent link") ----------------------------------------------------------------------------------- **Understanding the error message.** The error message tells you which other cells defined the multiply defined variable. You can click on the cell name, and marimo will highlight it. **Why can't I redefine variables?** marimo guarantees that the code on the page matches the outputs you see by determining a deterministic execution order on cells; when one cell runs, marimo knows which others should run. But if two cells defined `x`, and a third showed `x`, the output of the third cell would be ambiguous, depending on which of the defining cells ran first (should it be `0` or `1`?). That's a problem because it creates [hidden state and hidden bugs](https://docs.marimo.io/guides/coming_from/jupyter/), and it's part of the reason why [over 96% of Jupyter notebooks on GitHub aren't reproducible](https://leomurta.github.io/papers/pimentel2019a.pdf). **What do I get in return?** By accepting this constraint on variables, marimo makes your notebooks: * **reproducible**, with a well-defined execution order, no hidden state, and no hidden bugs; * **executable** as a script; * **interactive** with UI elements that work without callbacks; * **shareable as a web app**, with far better performance than streamlit. As a bonus, you'll find that you end up with cleaner, reusable code. How do I fix this error?[¶](#how-do-i-fix-this-error "Permanent link") ---------------------------------------------------------------------- You have a few options. ### Use local variables[¶](#use-local-variables "Permanent link") In marimo, variables prefixed with an underscore (`_x` or `_i`) are made local to a cell, and can be redefined across multiple cells. Use this in a pinch, but prefer encapsulating code in functions. ### Encapsulate code in a function[¶](#encapsulate-code-in-a-function "Permanent link") Python provides local scope through functions: if the variable that was redefined is meant to be a temporary variable, then you can make it local to the cell by encapsulating the code in a function. If any of the cell's variables are not meant to be local, or are outputs meant to be displayed, just return them from the function. In general, we recommend writing modular code with meaningful functions. But, in a pinch, just declare an anonymous function like this one to get a "local scope": `[](#__codelineno-1-1)def _(): [](#__codelineno-1-2) import matplotlib.pyplot as plt [](#__codelineno-1-3) fig, ax = plt.subplots() [](#__codelineno-1-4) ax.plot([1, 2]) [](#__codelineno-1-5) return ax [](#__codelineno-1-6)[](#__codelineno-1-7)_()` That's what clicking on the "Fix: Wrap in a function" button does. Note the function `_()` is local to the cell. ### Merge cells[¶](#merge-cells "Permanent link") Often you can simply merge the cells that define the same variable into a single cell. To incrementally show outputs in the cell, use [`mo.output.append`](https://docs.marimo.io/api/outputs/#marimo.output.append " marimo.output.append") or `print()`. ### Chain dataframe methods[¶](#chain-dataframe-methods "Permanent link") When working with dataframes, instead of splitting up operations across multiple cells, chain operations in a single cell. This is especially ergonomic when using [Polars](https://docs.pola.rs/), Daft, or other modern dataframe libraries that support lazy execution. Cycles - marimo https://docs.marimo.io/guides/understanding_errors/cycles/ You're probably on this page because you just saw an error like this one: marimo raises this error when a cell is involved in a cycle on variables. In this example, the first cell declares `a` and reads `b`, while the second cell declares `b` and reads `a`. Why can't I have cycles?[¶](#why-cant-i-have-cycles "Permanent link") --------------------------------------------------------------------- marimo parses your cells to understand the order in which they run: run a cell, and cells that refer to its defined variables need to run afterward. With a cycle, the execution order becomes ambiguous, while also introducing an infinite loop. **What do I get in return?** By accepting this constraint on variables, marimo makes your notebooks: * **reproducible**, with a well-defined execution order, no hidden state, and no hidden bugs; * **executable** as a script; * **interactive** with UI elements that work without callbacks; * **shareable as a web app**, with far better performance than streamlit. As a bonus, you'll find that you end up with cleaner, reusable code. **How do I read the error message?** In the error message, each line says which cell defines a variable and which cell reads a variable. For example, `cell-0 -> a` means `cell-0` defines `a`, and `a -> cell-1` means `cell-1` reads `a`. Similarly, `cell-1 -> b` means `cell-1` defines `b`, and `b -> cell-0` means `cell-0` reads `b`. This creates the cycle from `cell-0 -> cell-1 -> cell-0`. How do I fix this error?[¶](#how-do-i-fix-this-error "Permanent link") ---------------------------------------------------------------------- Cycles usually indicate that your notebook has a bug. Still, you can fix the error by merging the cells involved in the cycle into a single cell: Package management - marimo https://docs.marimo.io/guides/package_management/ The following guides cover how to import, install, and otherwise manage the Python dependencies of your notebooks. | Guide | Description | | --- | --- | | [Importing packages](https://docs.marimo.io/guides/package_management/importing_packages/) | How marimo finds packages on import | | [Installing packages](https://docs.marimo.io/guides/package_management/installing_packages/) | Installing packages with marimo's UI | | [Inlining dependencies](https://docs.marimo.io/guides/package_management/inlining_dependencies/) | Create self-contained notebooks by inlining dependencies in notebook files | | [Notebooks in existing projects](https://docs.marimo.io/guides/package_management/notebooks_in_projects/) | Working with marimo notebooks in existing Python projects | | [Using uv](https://docs.marimo.io/guides/package_management/using_uv/) | A guide to using the uv package manager with marimo | Setup References - marimo https://docs.marimo.io/guides/understanding_errors/setup/ You're probably on this page because you just saw an error like this one: marimo raises this error when the setup cell references variables defined in other cells. In the example above, `image` is defined elsewhere in the notebook, and hence cannot be referenced. Why can't I refer to variables?[¶](#why-cant-i-refer-to-variables "Permanent link") ----------------------------------------------------------------------------------- The setup cell special: it runs before all other cells run, in order to provide symbols that [top-level functions and classes](https://docs.marimo.io/guides/reusing_functions/) can use. That's why it can't reference variables defined by other cells. How do I fix this error?[¶](#how-do-i-fix-this-error "Permanent link") ---------------------------------------------------------------------- Define all needed variables in the setup cell. Or, if this code does not need to run before all other cells (if you are not using top-level functions or classes), simply move your code to a regular cell. Importing packages - marimo https://docs.marimo.io/guides/package_management/importing_packages/ By default, marimo searches for packages in the [virtual environment](https://docs.python.org/3/tutorial/venv.html) it was started in. For example, if you run `[](#__codelineno-0-1)source /path/to/venv/bin/activate [](#__codelineno-0-2)marimo edit my_notebook.py` you'll be able to import packages installed in the environment you just activated. You'll also be able to install packages into this environment using the marimo editor's [package management UI](https://docs.marimo.io/guides/package_management/installing_packages/). Using uv? See our [uv guide](https://docs.marimo.io/guides/package_management/using_uv/) for details on how to use marimo as part of uv projects or as self-contained scripts. Inlining dependencies[¶](#inlining-dependencies "Permanent link") ----------------------------------------------------------------- As an alternative to manually creating and managing a virtual environment, you can let marimo manage virtual environments for you, on a per-notebook basis. If you create a notebook with the `--sandbox` flag — `[](#__codelineno-1-1)marimo edit --sandbox my_notebook.py` — marimo will start your notebook in an isolated environment and keep track of the dependencies you install from the editor. These dependencies are inlined in the notebook file, so that the next time you run the notebook, marimo will run it in an isolated environment with just those dependencies. See our guide on [inlining dependencies](https://docs.marimo.io/guides/package_management/inlining_dependencies/) to learn more. What about kernels? Unlike Jupyter, marimo does not have a concept of "kernels"; notebooks simply use the active virtual environment. The main feature of kernels is to allow different notebooks to depend on different packages, even within the same project. marimo's package sandbox provides this functionality, while also being far simpler to use than custom kernels. Importing local modules[¶](#importing-local-modules "Permanent link") --------------------------------------------------------------------- marimo resolves imports just as Python does: by searching for packages in the directories listed in `sys.path`. That means that in addition to the virtual environment, marimo will search for modules in the directory in which the notebook lives. For example, when you run `[](#__codelineno-2-1)marimo edit /path/to/notebook_dir/notebook.py` marimo will look for modules in `/path/to/notebook_dir`. However, this means that you may need to take additional steps to import modules that live outside this directory. What steps you take depends on whether your code is organized as a Python package. Remember: notebooks are just Python programs In the examples below, notebooks are stored in a separate notebooks directory, which is traditional. However, since marimo notebooks are just Python modules, you can just as well include them in your `src/` directory alongside other Python modules. ### From non-package projects[¶](#from-non-package-projects "Permanent link") You can configure the Python path to accommodate directory structures that look like this: `[](#__codelineno-3-1). [](#__codelineno-3-2)├── notebooks [](#__codelineno-3-3)│   └── my_notebook.py [](#__codelineno-3-4)├── pyproject.toml [](#__codelineno-3-5)└── src [](#__codelineno-3-6) └── my_module.py` In particular, to make `import my_module` work when running editrunscript `[](#__codelineno-4-1)marimo edit notebooks/my_notebook.py` `[](#__codelineno-5-1)marimo run notebooks/my_notebook.py` `[](#__codelineno-6-1)python notebooks/my_notebook.py` add the following configuration to your `pyproject.toml`: pyproject.toml `[](#__codelineno-7-1)[tool.marimo.runtime] [](#__codelineno-7-2)pythonpath = ["src"]` ### From packages[¶](#from-packages "Permanent link") New to Python packages? A [Python package](https://docs.python.org/3/tutorial/modules.html#packages) is a way of structuring Python source files so that the collection of files can be installed in an environment, imported using "dot" notation like `from my_package.my_module import my_function`, and optionally uploaded to package registries like PyPI. If you are new to packages, and find you need to create one, we recommend using [uv](https://docs.astral.sh/uv/) (`uv init --package`). A package has a directory structure like this: `[](#__codelineno-8-1). [](#__codelineno-8-2)├── notebooks [](#__codelineno-8-3)│   └── my_notebook.py [](#__codelineno-8-4)├── pyproject.toml [](#__codelineno-8-5)└── src [](#__codelineno-8-6) └── my_package [](#__codelineno-8-7) ├── __init__.py [](#__codelineno-8-8) └── my_module.py` Say `my_notebook` has a cell with `[](#__codelineno-9-1)from my_package import my_module` Provided that editrunscript `[](#__codelineno-10-1)marimo edit notebooks/my_notebook.py` `[](#__codelineno-11-1)marimo run notebooks/my_notebook.py` `[](#__codelineno-12-1)python notebooks/my_notebook.py` is run from an environment in which your package is installed, marimo will import `my_module` without issue. For example, if you are using `uv`, simply run `[](#__codelineno-13-1)uv run --with marimo marimo edit notebooks/my_notebook.py` Installing packages - marimo https://docs.marimo.io/guides/package_management/installing_packages/ marimo supports package management for `pip`, `uv`, `poetry`, `pixi`, and `rye`. When marimo comes across a module that is not installed, you will be prompted to install it using your preferred package manager. Once the module is installed, all cells that depend on the module will be rerun (or marked as stale). You can also install (and remove) packages using the package manager sidebar panel. Resolving package names We use a heuristic for guessing the package name in your registry (e.g. PyPI) from the module name. It is possible that the package name is different from the module name. If you encounter an error, please [file an issue](https://github.com/marimo-team/marimo/issues) or help us by adding your mapping [directly to the codebase](https://github.com/marimo-team/marimo/blob/main/marimo/_runtime/packages/module_name_to_pypi_name.py). **Notes.** * When using imperative style package managers like `pip`, packages are installed directly in the active virtual environment. * When using `uv`, marimo will decide whether to add it to your `pyproject.toml` (if running as part of a uv project), or whether to install it imperatively with `uv pip` (otherwise). * When running in a [package sandbox](https://docs.marimo.io/guides/package_management/inlining_dependencies/), package installation and removal also updates the notebook's inline dependencies. Inlining dependencies - marimo https://docs.marimo.io/guides/package_management/inlining_dependencies/ marimo is the only Python notebook that is reproducible down to the packages, letting you inline Python dependencies in notebook files and running notebooks in isolated or "sandboxed" venvs. This lets you share standalone notebooks without shipping `requirements.txt` files alongside them, and guarantees your notebooks will work weeks, months, even years into the future. To opt-in to dependency inlining, use the `sandbox` flag: editrunnew `[](#__codelineno-0-1)marimo edit --sandbox notebook.py` `[](#__codelineno-1-1)marimo run --sandbox notebook.py` When running with `--sandbox`, marimo: 1. tracks the packages and versions used by your notebook, saving them in the notebook file; 2. runs in an isolated virtual environment ("sandbox") that only contains the notebook dependencies. marimo's sandbox provides two key benefits. (1) Notebooks that carry their own dependencies are easy to share — just send the `.py` file. (2) Isolating a notebook from other installed packages prevents obscure bugs. Sandboxed Home You can also use `--sandbox` when editing a folder of notebooks. Each notebook gets its own isolated environment. See [Sandboxed Home](https://docs.marimo.io/guides/editor_features/home/#sandboxed-home). You can also run sandboxed notebooks as scripts: Solving the notebook reproducibility crisis marimo's support for package sandboxing is only possible because marimo notebooks are stored as pure Python files, letting marimo take advantage of new Python standards like [PEP 723](https://peps.python.org/pep-0723/) and tools like uv. In contrast, traditional notebooks like Jupyter are stored as JSON files, and which suffer from a [reproducibility crisis](https://leomurta.github.io/papers/pimentel2019a.pdf) due to the lack of package management. When running with `--sandbox`, marimo automatically tracks package metadata in your notebook file using inline script metadata, which per [PEP 723](https://peps.python.org/pep-0723/) is essentially a pyproject.toml inlined as the script's header. This metadata is used to manage the notebook's dependencies and Python version, and looks something like this: `[](#__codelineno-4-1)# /// script [](#__codelineno-4-2)# requires-python = ">=3.11" [](#__codelineno-4-3)# dependencies = [ [](#__codelineno-4-4)# "pandas==", [](#__codelineno-4-5)# "altair==", [](#__codelineno-4-6)# ] [](#__codelineno-4-7)# ///` Example notebooks The [example notebooks](https://github.com/marimo-team/marimo/tree/main/examples) in our GitHub repo were all created using `--sandbox`. Take a look at any of them for an example of the full script metadata. ### Adding and removing packages[¶](#adding-and-removing-packages "Permanent link") **Using the marimo editor.** When you import a module in the marimo editor, if marimo detects that it is a third-party package, it will automatically be added to the script metadata. Removing an import does _not_ remove it from the script metadata (since library code may still use the package). Adding packages via the package manager panel will also add packages to script metadata, and removing packages from the panel will in turn remove them from the script metadata. **Adding packages manually.** You can manually manage your notebook's requirements: * edit the script metadata manually in an editor like VS Code or neovim. * use `uv` from the command-line: `[](#__codelineno-5-1)uv add --script notebook.py numpy` `[](#__codelineno-6-1)uv remove --script notebook.py numpy` ### Package locations[¶](#package-locations "Permanent link") By default, marimo will look for packages on PyPI. You can edit the script metadata to look for packages elsewhere, such as on GitHub. Consult the [Python packaging documentation](https://packaging.python.org/en/latest/specifications/dependency-specifiers/#examples) for more information. ### Local development with editable installs[¶](#local-development-with-editable-installs "Permanent link") When developing a local package, you can install it in editable mode using the `[tool.uv.sources]` section in the script metadata. For example: `[](#__codelineno-7-1)# /// script [](#__codelineno-7-2)# requires-python = ">=3.11" [](#__codelineno-7-3)# dependencies = [ [](#__codelineno-7-4)# "my-package", [](#__codelineno-7-5)# ] [](#__codelineno-7-6)# [](#__codelineno-7-7)# [tool.uv.sources] [](#__codelineno-7-8)# my-package = { path = "../", editable = true } [](#__codelineno-7-9)# ///` This is particularly useful when you want to test changes to your package without reinstalling it. The package will be installed in "editable" mode, meaning changes to the source code will be reflected immediately in your notebook. ### Specifying alternative package indexes[¶](#specifying-alternative-package-indexes "Permanent link") When you need to use packages from a custom PyPI server or alternative index, you can specify these in your script metadata using the `[[tool.uv.index]]` section. This is useful for private packages or when you want to use packages from a specific source. `[](#__codelineno-8-1)# /// script [](#__codelineno-8-2)# requires-python = ">=3.11" [](#__codelineno-8-3)# dependencies = [ [](#__codelineno-8-4)# "pandas==", [](#__codelineno-8-5)# "private-package==", [](#__codelineno-8-6)# ] [](#__codelineno-8-7)# [](#__codelineno-8-8)# [[tool.uv.index]] [](#__codelineno-8-9)# name = "custom-index" [](#__codelineno-8-10)# url = "https://custom-pypi-server.example.com/simple/" [](#__codelineno-8-11)# explicit = true [](#__codelineno-8-12)# [](#__codelineno-8-13)# [tool.uv.sources] [](#__codelineno-8-14)# private-package = { index = "custom-index" } [](#__codelineno-8-15)# ///` In this example: * `[[tool.uv.index]]` defines a custom package index * `name` is an identifier for the index * `url` points to your custom PyPI server * `explicit = true` means this index will only be used for packages explicitly associated with it * `[tool.uv.sources]` specifies which packages should come from which indexes This approach ensures that specific packages are always fetched from your designated custom index, while other packages continue to be fetched from the default PyPI repository. Configuration[¶](#configuration "Permanent link") ------------------------------------------------- Running marimo in a sandbox environment uses `uv` to create an isolated virtual environment. You can use any of `uv`'s [supported environment variables](https://docs.astral.sh/uv/configuration/environment/). ### Choosing the Python version[¶](#choosing-the-python-version "Permanent link") For example, you can specify the Python version using the `UV_PYTHON` environment variable: `[](#__codelineno-9-1)UV_PYTHON=3.13 marimo edit --sandbox notebook.py` ### Other common configuration[¶](#other-common-configuration "Permanent link") Another common configuration is `uv`'s link mode: `[](#__codelineno-10-1)UV_LINK_MODE="copy" marimo edit --sandbox notebook.py` Sharing on the web[¶](#sharing-on-the-web "Permanent link") ----------------------------------------------------------- You can also upload sandboxed notebooks to the web, such as on GitHub, and have others run them locally with a single command: `[](#__codelineno-11-1)uvx marimo edit --sandbox https://gist.githubusercontent.com/kolibril13/a59135dd0973b97d488ba21c650667fe/raw/5f98021b5d3c024d5827fa9464787517495178b4/marimo_minimal_numpy_example.py` **Note:** 1. This command will run code from a URL. Make sure you trust the source before proceeding. 2. Upon execution, you’ll be prompted: `[](#__codelineno-12-1)Would you like to run it in a secure docker container? [Y/n]:` To proceed securely, ensure you have [Docker](https://www.docker.com/) installed and running, then press `Y`. Specifying dependencies in Markdown files[¶](#specifying-dependencies-in-markdown-files "Permanent link") --------------------------------------------------------------------------------------------------------- Sandboxing support is also provided in [marimo's markdown file format](https://docs.marimo.io/guides/editor_features/watching/#as-markdown) under the `pyproject` entry of your frontmatter. `[](#__codelineno-13-1)--- [](#__codelineno-13-2)title: My Notebook [](#__codelineno-13-3)marimo-version: 0.0.0 [](#__codelineno-13-4)pyproject: | [](#__codelineno-13-5) requires-python: ">=3.11" [](#__codelineno-13-6) dependencies: [](#__codelineno-13-7) - pandas== [](#__codelineno-13-8) - altair== [](#__codelineno-13-9)---` Notebooks in existing projects - marimo https://docs.marimo.io/guides/package_management/notebooks_in_projects/ When working with notebooks in existing projects, there are two main approaches depending on your needs: 1. **Sandbox notebooks** - Self-contained notebooks with isolated dependencies 2. **Project notebooks** - Notebooks that are part of your project's environment marimo uses [PEP 723](https://peps.python.org/pep-0723/) inline script metadata for sandboxing, managed by uv. While sandboxing is currently exclusive to the uv package manager, other package managers may be supported in the future. For project notebooks, marimo can be added as a project dependency where all notebooks share the same environment defined in `pyproject.toml`. This approach works with uv and other package managers (Poetry, Pixi, Hatch, etc.). Sandbox notebooks (recommended for libraries)[¶](#sandbox-notebooks-recommended-for-libraries "Permanent link") --------------------------------------------------------------------------------------------------------------- Sandbox notebooks use inline script metadata ([PEP 723](https://peps.python.org/pep-0723/)) to create isolated environments. This is ideal when: * Building examples for a library that users can run independently * Creating notebooks that don't share dependencies with your main project * Sharing self-contained notebooks that work anywhere ### Basic sandbox notebook[¶](#basic-sandbox-notebook "Permanent link") Sandbox notebooks can be created with: `[](#__codelineno-0-1)marimo edit --sandbox notebook.py` When working in the notebook, marimo will automatically manage PEP 723 metadata for you. This metadata makes the notebook self-contained, meaning you can either come back later with marimo or run the notebook as a script directly with uv: `[](#__codelineno-1-1)marimo edit --sandbox notebook.py # automatically loads deps and launches marimo [](#__codelineno-1-2)uv run notebook.py # run notebook as a script` ### Developing against your local package[¶](#developing-against-your-local-package "Permanent link") When developing library examples, tutorials, or exploratory code, it's often useful to have notebooks that _use_ your library. In these cases, you can create and version sandboxed notebooks with your library as an _editable_ install. This approach lets you: * Test your library changes immediately without reinstalling * Add notebook-specific dependencies (like visualization or data processing tools) without polluting your library's requirements * Create self-contained examples that users can run without your development dependencies To add your library to a notebook, use uv: `[](#__codelineno-2-1)uv add --script notebooks/notebook.py . --editable` This will produce a header that looks like: `[](#__codelineno-3-1)# /// script [](#__codelineno-3-2)# requires-python = ">=3.11" [](#__codelineno-3-3)# dependencies = [ [](#__codelineno-3-4)# "my-package", [](#__codelineno-3-5)# "pandas", [](#__codelineno-3-6)# "matplotlib", [](#__codelineno-3-7)# ] [](#__codelineno-3-8)# [](#__codelineno-3-9)# [tool.uv.sources] [](#__codelineno-3-10)# my-package = { path = "../", editable = true } [](#__codelineno-3-11)# ///` Project notebooks[¶](#project-notebooks "Permanent link") --------------------------------------------------------- For notebooks that are integral to your project, you can manage everything through your project's `pyproject.toml`. This approach uses a single environment shared between your project and notebooks. ### Adding marimo to your project[¶](#adding-marimo-to-your-project "Permanent link") `[](#__codelineno-4-1)[project] [](#__codelineno-4-2)name = "my-project" [](#__codelineno-4-3)dependencies = [ [](#__codelineno-4-4) "numpy", [](#__codelineno-4-5) "requests", [](#__codelineno-4-6)] [](#__codelineno-4-7)[](#__codelineno-4-8)[dependency-groups] [](#__codelineno-4-9)dev = [ [](#__codelineno-4-10) "marimo", [](#__codelineno-4-11) "pytest", [](#__codelineno-4-12)]` Then work with notebooks using your project's environment: `[](#__codelineno-5-1)# Using uv [](#__codelineno-5-2)uv run marimo edit notebooks/analysis.py [](#__codelineno-5-3)[](#__codelineno-5-4)# Or activate the environment [](#__codelineno-5-5)source .venv/bin/activate [](#__codelineno-5-6)marimo edit notebooks/analysis.py` This approach: - Uses a single environment for everything - Shares dependencies between notebooks and your project - Follows standard Python project practices Importing from other directories If your notebooks need to import modules from directories outside your project, marimo supports configuring the Python path via `pyproject.toml`. However, when possible, it's preferred to avoid path manipulation. We recommend creating a package (`uv init --lib`) and including marimo as a development dependency. For multiple packages, consider configuring [uv workspaces](https://docs.astral.sh/uv/concepts/workspaces/). See the [runtime configuration guide](https://docs.marimo.io/guides/configuration/runtime_configuration/#python-path) for details. Examples[¶](#examples "Permanent link") --------------------------------------- ### Library with example notebooks[¶](#library-with-example-notebooks "Permanent link") When building a library, use sandbox notebooks for examples that users can run independently: `[](#__codelineno-6-1)my-library/ [](#__codelineno-6-2)├── pyproject.toml # Library dependencies [](#__codelineno-6-3)├── src/ [](#__codelineno-6-4)│ └── my_library/ [](#__codelineno-6-5)└── examples/ [](#__codelineno-6-6) ├── quickstart.py # Sandbox notebook [](#__codelineno-6-7) └── advanced.py # Sandbox notebook` Create example notebooks: `[](#__codelineno-7-1)# Initialize the project [](#__codelineno-7-2)uv init --lib my-library && cd my-library [](#__codelineno-7-3)[](#__codelineno-7-4)# Add marimo as development dependency [](#__codelineno-7-5)uv add --dev marimo [](#__codelineno-7-6)[](#__codelineno-7-7)# Create a sandbox notebook [](#__codelineno-7-8)mkdir examples [](#__codelineno-7-9)uv run marimo edit --sandbox examples/quickstart.py [](#__codelineno-7-10)[](#__codelineno-7-11)# Add your library as editable dependency [](#__codelineno-7-12)uv add --script examples/quickstart.py . --editable` ### Data science project[¶](#data-science-project "Permanent link") When notebooks are part of your analysis workflow, use project notebooks: `[](#__codelineno-8-1)analysis-project/ [](#__codelineno-8-2)├── pyproject.toml # Project + marimo dependencies [](#__codelineno-8-3)├── README.md [](#__codelineno-8-4)├── main.py # Created by uv init [](#__codelineno-8-5)└── notebook.py # Your marimo notebook` Set up the project: `[](#__codelineno-9-1)# Initialize project [](#__codelineno-9-2)uv init analysis-project && cd analysis-project [](#__codelineno-9-3)[](#__codelineno-9-4)# Add marimo as a project dependency [](#__codelineno-9-5)uv add marimo pandas scikit-learn [](#__codelineno-9-6)[](#__codelineno-9-7)# Edit notebooks using project environment [](#__codelineno-9-8)uv run marimo edit notebook.py` * [Using uv](https://docs.marimo.io/guides/package_management/using_uv/) - Detailed guide on uv with marimo * [Inlining dependencies](https://docs.marimo.io/guides/package_management/inlining_dependencies/) - More on self-contained notebooks * [Package management overview](https://docs.marimo.io/guides/package_management/) - General package management in marimo Generate with AI - marimo https://docs.marimo.io/guides/generate_with_ai/ Generate notebooks with AI[¶](#generate-notebooks-with-ai "Permanent link") --------------------------------------------------------------------------- | Guide | Description | | --- | --- | | [Skills](https://docs.marimo.io/guides/generate_with_ai/skills/) | Skills for coding agents | | [Zero-shot entire notebooks](https://docs.marimo.io/guides/generate_with_ai/text_to_notebook/) | Generate entire notebooks with AI | | [AI-assisted coding](https://docs.marimo.io/guides/editor_features/ai_completion/) | Refactor code and generate cells with AI | | [Prompts for the marimo editor](https://docs.marimo.io/guides/generate_with_ai/prompts/) | Collection of prompts to speed up workflows in marimo | | [Using Claude Code](https://docs.marimo.io/guides/generate_with_ai/using_claude_code/) | Collection of utilities to get the most out of Claude Code | Using uv - marimo https://docs.marimo.io/guides/package_management/using_uv/ [uv](https://docs.astral.sh/uv/) is an extremely fast Python package and project manager: you can use it to install packages, manage the dependencies of Python projects, and run scripts. While marimo supports all major package managers, it integrates especially tightly with uv. In particular, marimo's package sandbox feature, which lets you [inline dependencies](https://docs.marimo.io/guides/package_management/inlining_dependencies/) in notebook files, requires uv. No prior knowledge required This guide teaches you the basics of using `uv` with marimo. It assumes zero familiarity with `uv`. You can manage your notebooks' dependencies in three different ways: 1. inline dependencies: [inlining dependencies](https://docs.marimo.io/guides/package_management/inlining_dependencies/) in notebook files, using `marimo edit --sandbox notebook.py` 2. projects: using a `uv` project , which define dependencies declaratively in a `pyproject.toml` file; 3. non-project environment: dependencies are imperatively installed We'll walk through each of these three ways in this guide. Using inline dependencies[¶](#using-inline-dependencies "Permanent link") ------------------------------------------------------------------------- The easiest way to get started is to use marimo's [package sandbox feature](https://docs.marimo.io/guides/package_management/inlining_dependencies/), which manages your dependencies for you. Create or edit your notebook with [`uvx` command](https://docs.astral.sh/uv/concepts/tools/#the-uv-tool-interface), making sure to include the `--sandbox` flag: `[](#__codelineno-0-1)uvx marimo edit --sandbox my_notebook.py` This command installs marimo in a temporary environment, activates it, then runs your marimo notebook. The `--sandbox` flag is what tells marimo to keep track of your dependencies and store them in the notebook file. If there are any dependencies already tracked in the file, this command will download them and install them in the environment. Run sandboxed notebooks as scripts with ### From URLs[¶](#from-urls "Permanent link") You can also upload sandboxed notebooks to the web, such as on GitHub, and have others run them locally with a single command: `[](#__codelineno-2-1)uvx marimo edit --sandbox https://gist.githubusercontent.com/kolibril13/a59135dd0973b97d488ba21c650667fe/raw/5f98021b5d3c024d5827fa9464787517495178b4/marimo_minimal_numpy_example.py` **Note:** 1. This command will run code from a URL. Make sure you trust the source before proceeding. 2. Upon execution, you’ll be prompted: `[](#__codelineno-3-1)Would you like to run it in a secure docker container? [Y/n]:` To proceed securely, ensure you have [Docker](https://www.docker.com/) installed and running, then press `Y`. To learn more, read our full guide on using [inline dependencies](https://docs.marimo.io/guides/package_management/inlining_dependencies/). Using uv projects[¶](#using-uv-projects "Permanent link") --------------------------------------------------------- A [`uv` project](https://docs.astral.sh/uv/guides/projects/) is a directory in which you can store Python code, including notebooks, alongside a pyproject.toml file that declares the project's dependencies. ### Creating a project[¶](#creating-a-project "Permanent link") Create a project with `uv init`: `[](#__codelineno-4-1)uv init hello-world [](#__codelineno-4-2)cd hello-world` This creates a pyproject.toml and some starter code. Next, add marimo to your project: Omitting marimo from your project Adding marimo to your project is optional. Instead, you can run marimo in a temporary environment that has access to your project's dependencies using `uv run --with marimo marimo edit`. ### Running marimo[¶](#running-marimo "Permanent link") Once you've added marimo, use the `uv run` command to run the version of marimo installed in your project: `[](#__codelineno-6-1)uv run marimo edit my_notebook.py` Starting marimo in this way will let marimo import any of the packages installed in your project. **Scripts.** Run marimo notebooks as scripts with which will run your notebook in an environment containing your project dependencies. ### Adding and removing dependencies[¶](#adding-and-removing-dependencies "Permanent link") #### Using the uv command-line[¶](#using-the-uv-command-line "Permanent link") Use `uv add` to add dependencies: You can also specify a version Remove packages with `uv remove`: #### Using the marimo editor[¶](#using-the-marimo-editor "Permanent link") If you started marimo with `uv run marimo edit`, the marimo editor's [package management features](https://docs.marimo.io/guides/package_management/installing_packages/) will add and remove packages from your pyproject.toml, so there's no need to use the `uv` command-line if you don't want to. Using marimo in a non-project environment[¶](#using-marimo-in-a-non-project-environment "Permanent link") --------------------------------------------------------------------------------------------------------- If you are used to a venv and pip based workflow, you can use the `uv venv` and `uv pip` commands for a similar but more performant experience: * `uv venv` creates a virtual environment in the current directory, at `.venv` * `uv pip` lets you install and uninstall packages in the venv ### Example[¶](#example "Permanent link") `[](#__codelineno-11-1)$ uv venv [](#__codelineno-11-2)$ uv pip install numpy [](#__codelineno-11-3)$ uv pip install marimo [](#__codelineno-11-4)$ uv run marimo edit` From here, `import numpy` will work within the notebook, and marimo's UI installer will add packages to the environment with `uv pip install` on your behalf. Generate entire notebooks - marimo https://docs.marimo.io/guides/generate_with_ai/text_to_notebook/ Use [`marimo new`](https://docs.marimo.io/cli/#marimo-new) at the command line to generate entirely new notebooks using an LLM. For example, type `[](#__codelineno-0-1)marimo new "Plot an interactive 3D surface with matplotlib."` to open a freshly generated notebook in your browser. For long prompts, you can pass a text file instead: marimo's AI knows how to use marimo-specific UI elements and popular libraries for working with data. To get inspired, visit [https://marimo.app/ai](https://marimo.app/ai). Some of our favorites: * [Dimensionality reduction](https://marimo.app/ai?q=Show+me+how+to+visualize+handwritten+digits+in+two+dimensions%2C+using+an+Altair+scatterplot.+Include+a+cell+that+shows+the+chart+value.+Make+the+chart+render+as+a+square.) * [Smooth a time series](https://marimo.app/ai?q=Show+me+how+to+smooth+time+series+data+and+plot+it.+Use+a+well-known+stock+dataset+and+make+it+interactive) * [Compute code complexity](https://marimo.app/ai?q=Build+a+tool+that+analyzes+Python+code+complexity+metrics+like+cyclomatic+complexity.+Let+me+input+code+snippets+and+see+visualizations+of+the+results.) * [Visualize sorting algorithms](https://marimo.app/ai?q=Plot+an+interesting+3D+surface+with+matplotlib.+Include+an+interactive+element+to+control+the+shape+of+the+surface.) Skills - marimo https://docs.marimo.io/guides/generate_with_ai/skills/ We have prepared a collection of skills to help coding agents work with marimo. Install our official skills with a single command: `[](#__codelineno-0-1)npx skills add marimo-team/skills` **Use cases.** Use these skills to * convert Jupyter notebooks or other artifacts to marimo notebooks, * make bespoke interactive UI elements or widgets for specific use cases, * and otherwise author high-quality standalone notebooks. **Feedback.** We welcome feedback at our [GitHub repository](https://github.com/marimo-team/skills/issues). Watching for changes to notebooks on disk When using marimo with Claude Code, configure the marimo editor to automatically reload when Claude edits your notebook by starting marimo with the `watch` flag: `marimo edit --watch notebook.py`. (Learn more in our [watching guide](https://docs.marimo.io/guides/editor_features/watching/).) You can also configure marimo to automatically reload affected cells when auxiliary files change on disk using [module autoreloading](https://docs.marimo.io/guides/editor_features/module_autoreloading/). What are skills?[¶](#what-are-skills "Permanent link") ------------------------------------------------------ Skills are folders of instructions, scripts, and resources that Claude and other agents load dynamically to improve performance on specialized tasks. To learn more about skills, check out: * [What are skills?](https://support.claude.com/en/articles/12512176-what-are-skills) * [Using skills in Claude](https://support.claude.com/en/articles/12512180-using-skills-in-claude) * [skills.sh](https://skills.sh/) Prompts - marimo https://docs.marimo.io/guides/generate_with_ai/prompts/ marimo offers many tools for [AI assisted coding](https://docs.marimo.io/guides/editor_features/ai_completion/). However, sometimes you may want to do something more custom and could benefit from a prompt template to get started from. The goal of this page is to share prompts that have proven to be useful and will help you get started on specific tasks. You can add these prompts to your [custom rules](https://docs.marimo.io/guides/editor_features/ai_completion/#custom-rules) but be mindful that doing so will make every call to the LLM more expensive because you're feeding it more tokens. That's why we generally recommend to start your conversations with these snippets if you don't plan on using them very often. AGENTS.md and CLAUDE.md[¶](#agentsmd-and-claudemd "Permanent link") ------------------------------------------------------------------- You can run tools like [claude code](https://www.anthropic.com/claude-code) or [codex](https://openai.com/codex/) in the terminal and ask it to edit a marimo notebook on your behalf. Make sure that you run your notebook with the [watch flag](https://docs.marimo.io/api/watch/) turned on, like `marimo edit --watch notebook.py`, to see updates appear live whenever the agent makes a change. To help your agent, you might want to take the snippet below as starting context for your `CLAUDE.md`/`AGENTS.md` file. This snippet should be seen as a starting point and we recommend adding extra context yourself. Things like "prefer polars over pandas" to indicate your preferred libraries and tools. `[](#__codelineno-0-1)curl https://docs.marimo.io/CLAUDE.md > CLAUDE.md` Example CLAUDE.md file `[](#__codelineno-1-1)# Marimo notebook assistant [](#__codelineno-1-2)[](#__codelineno-1-3)I am a specialized AI assistant designed to help create data science notebooks using marimo. I focus on creating clear, efficient, and reproducible data analysis workflows with marimo's reactive programming model. [](#__codelineno-1-4)[](#__codelineno-1-5)If you make edits to the notebook, only edit the contents inside the function decorator with @app.cell. [](#__codelineno-1-6)marimo will automatically handle adding the parameters and return statement of the function. For example, [](#__codelineno-1-7)for each edit, just return:` @app.cell def _(): return ``[](#__codelineno-2-1)## Marimo fundamentals [](#__codelineno-2-2)[](#__codelineno-2-3)Marimo is a reactive notebook that differs from traditional notebooks in key ways: [](#__codelineno-2-4)[](#__codelineno-2-5)- Cells execute automatically when their dependencies change [](#__codelineno-2-6)- Variables cannot be redeclared across cells [](#__codelineno-2-7)- The notebook forms a directed acyclic graph (DAG) [](#__codelineno-2-8)- The last expression in a cell is automatically displayed [](#__codelineno-2-9)- UI elements are reactive and update the notebook automatically [](#__codelineno-2-10)[](#__codelineno-2-11)## Code Requirements [](#__codelineno-2-12)[](#__codelineno-2-13)1. All code must be complete and runnable [](#__codelineno-2-14)2. Follow consistent coding style throughout [](#__codelineno-2-15)3. Include descriptive variable names and helpful comments [](#__codelineno-2-16)4. Import all modules in the first cell, always including `import marimo as mo` [](#__codelineno-2-17)5. Never redeclare variables across cells [](#__codelineno-2-18)6. Ensure no cycles in notebook dependency graph [](#__codelineno-2-19)7. The last expression in a cell is automatically displayed, just like in Jupyter notebooks. [](#__codelineno-2-20)8. Don't include comments in markdown cells [](#__codelineno-2-21)9. Don't include comments in SQL cells [](#__codelineno-2-22)10. Never define anything using `global`. [](#__codelineno-2-23)[](#__codelineno-2-24)## Reactivity [](#__codelineno-2-25)[](#__codelineno-2-26)Marimo's reactivity means: [](#__codelineno-2-27)[](#__codelineno-2-28)- When a variable changes, all cells that use that variable automatically re-execute [](#__codelineno-2-29)- UI elements trigger updates when their values change without explicit callbacks [](#__codelineno-2-30)- UI element values are accessed through `.value` attribute [](#__codelineno-2-31)- You cannot access a UI element's value in the same cell where it's defined [](#__codelineno-2-32)- Cells prefixed with an underscore (e.g. _my_var) are local to the cell and cannot be accessed by other cells [](#__codelineno-2-33)[](#__codelineno-2-34)## Best Practices [](#__codelineno-2-35)[](#__codelineno-2-36) [](#__codelineno-2-37)[](#__codelineno-2-38)- Use polars for data manipulation [](#__codelineno-2-39)- Implement proper data validation [](#__codelineno-2-40)- Handle missing values appropriately [](#__codelineno-2-41)- Use efficient data structures [](#__codelineno-2-42)- A variable in the last expression of a cell is automatically displayed as a table [](#__codelineno-2-43) [](#__codelineno-2-44)[](#__codelineno-2-45) [](#__codelineno-2-46)- For matplotlib: use plt.gca() as the last expression instead of plt.show() [](#__codelineno-2-47)- For plotly: return the figure object directly [](#__codelineno-2-48)- For altair: return the chart object directly. Add tooltips where appropriate. You can pass polars dataframes directly to altair. [](#__codelineno-2-49)- Include proper labels, titles, and color schemes [](#__codelineno-2-50)- Make visualizations interactive where appropriate [](#__codelineno-2-51) [](#__codelineno-2-52)[](#__codelineno-2-53) [](#__codelineno-2-54)[](#__codelineno-2-55)- Access UI element values with .value attribute (e.g., slider.value) [](#__codelineno-2-56)- Create UI elements in one cell and reference them in later cells [](#__codelineno-2-57)- Create intuitive layouts with mo.hstack(), mo.vstack(), and mo.tabs() [](#__codelineno-2-58)- Prefer reactive updates over callbacks (marimo handles reactivity automatically) [](#__codelineno-2-59)- Group related UI elements for better organization [](#__codelineno-2-60) [](#__codelineno-2-61)[](#__codelineno-2-62) [](#__codelineno-2-63)- When writing duckdb, prefer using marimo's SQL cells, which start with df = mo.sql(f"""""") for DuckDB, or df = mo.sql(f"""""", engine=engine) for other SQL engines. [](#__codelineno-2-64)- See the SQL with duckdb example for an example on how to do this [](#__codelineno-2-65)- Don't add comments in cells that use mo.sql() [](#__codelineno-2-66) [](#__codelineno-2-67)[](#__codelineno-2-68)## Troubleshooting [](#__codelineno-2-69)[](#__codelineno-2-70)Common issues and solutions: [](#__codelineno-2-71)[](#__codelineno-2-72)- Circular dependencies: Reorganize code to remove cycles in the dependency graph [](#__codelineno-2-73)- UI element value access: Move access to a separate cell from definition [](#__codelineno-2-74)- Visualization not showing: Ensure the visualization object is the last expression [](#__codelineno-2-75)[](#__codelineno-2-76)After generating a notebook, run `marimo check --fix` to catch and [](#__codelineno-2-77)automatically resolve common formatting issues, and detect common pitfalls. [](#__codelineno-2-78)[](#__codelineno-2-79)## Available UI elements [](#__codelineno-2-80)[](#__codelineno-2-81)- `mo.ui.altair_chart(altair_chart)` [](#__codelineno-2-82)- `mo.ui.button(value=None, kind='primary')` [](#__codelineno-2-83)- `mo.ui.run_button(label=None, tooltip=None, kind='primary')` [](#__codelineno-2-84)- `mo.ui.checkbox(label='', value=False)` [](#__codelineno-2-85)- `mo.ui.date(value=None, label=None, full_width=False)` [](#__codelineno-2-86)- `mo.ui.dropdown(options, value=None, label=None, full_width=False)` [](#__codelineno-2-87)- `mo.ui.file(label='', multiple=False, full_width=False)` [](#__codelineno-2-88)- `mo.ui.number(value=None, label=None, full_width=False)` [](#__codelineno-2-89)- `mo.ui.radio(options, value=None, label=None, full_width=False)` [](#__codelineno-2-90)- `mo.ui.refresh(options: List[str], default_interval: str)` [](#__codelineno-2-91)- `mo.ui.slider(start, stop, value=None, label=None, full_width=False, step=None)` [](#__codelineno-2-92)- `mo.ui.range_slider(start, stop, value=None, label=None, full_width=False, step=None)` [](#__codelineno-2-93)- `mo.ui.table(data, columns=None, on_select=None, sortable=True, filterable=True)` [](#__codelineno-2-94)- `mo.ui.text(value='', label=None, full_width=False)` [](#__codelineno-2-95)- `mo.ui.text_area(value='', label=None, full_width=False)` [](#__codelineno-2-96)- `mo.ui.data_explorer(df)` [](#__codelineno-2-97)- `mo.ui.dataframe(df)` [](#__codelineno-2-98)- `mo.ui.plotly(plotly_figure)` [](#__codelineno-2-99)- `mo.ui.tabs(elements: dict[str, mo.ui.Element])` [](#__codelineno-2-100)- `mo.ui.array(elements: list[mo.ui.Element])` [](#__codelineno-2-101)- `mo.ui.form(element: mo.ui.Element, label='', bordered=True)` [](#__codelineno-2-102)[](#__codelineno-2-103)## Layout and utility functions [](#__codelineno-2-104)[](#__codelineno-2-105)- `mo.md(text)` - display markdown [](#__codelineno-2-106)- `mo.stop(predicate, output=None)` - stop execution conditionally [](#__codelineno-2-107)- `mo.output.append(value)` - append to the output when it is not the last expression [](#__codelineno-2-108)- `mo.output.replace(value)` - replace the output when it is not the last expression [](#__codelineno-2-109)- `mo.Html(html)` - display HTML [](#__codelineno-2-110)- `mo.image(image)` - display an image [](#__codelineno-2-111)- `mo.hstack(elements)` - stack elements horizontally [](#__codelineno-2-112)- `mo.vstack(elements)` - stack elements vertically [](#__codelineno-2-113)- `mo.tabs(elements)` - create a tabbed interface [](#__codelineno-2-114)[](#__codelineno-2-115)## Examples [](#__codelineno-2-116)[](#__codelineno-2-117)`` @app.cell def \_(): mo.md(""" # Hello world This is a \_markdown_ **cell**. """) return `[](#__codelineno-3-1) [](#__codelineno-3-2)[](#__codelineno-3-3)` @app.cell def \_(): import marimo as mo import altair as alt import polars as pl import numpy as np return @app.cell def \_(): n\_points = mo.ui.slider(10, 100, value=50, label="Number of points") n\_points return @app.cell def \_(): x = np.random.rand(n\_points.value) y = np.random.rand(n\_points.value) `df = pl.DataFrame({"x": x, "y": y}) chart = alt.Chart(df).mark_circle(opacity=0.7).encode( x=alt.X('x', title='X axis'), y=alt.Y('y', title='Y axis') ).properties( title=f"Scatter plot with {n_points.value} points", width=400, height=300 ) chart return` `[](#__codelineno-4-1) [](#__codelineno-4-2)[](#__codelineno-4-3)` @app.cell def \_(): import marimo as mo import polars as pl from vega\_datasets import data return @app.cell def \_(): cars\_df = pl.DataFrame(data.cars()) mo.ui.data\_explorer(cars\_df) return `[](#__codelineno-5-1) [](#__codelineno-5-2)[](#__codelineno-5-3)` @app.cell def \_(): import marimo as mo import polars as pl import altair as alt return @app.cell def \_(): iris = pl.read\_csv("hf://datasets/scikit-learn/iris/Iris.csv") return @app.cell def \_(): species\_selector = mo.ui.dropdown( options=\["All"\] + iris\["Species"\].unique().to\_list(), value="All", label="Species", ) x\_feature = mo.ui.dropdown( options=iris.select(pl.col(pl.Float64, pl.Int64)).columns, value="SepalLengthCm", label="X Feature", ) y\_feature = mo.ui.dropdown( options=iris.select(pl.col(pl.Float64, pl.Int64)).columns, value="SepalWidthCm", label="Y Feature", ) mo.hstack(\[species\_selector, x\_feature, y\_feature\]) return @app.cell def \_(): filtered\_data = iris if species\_selector.value == "All" else iris.filter(pl.col("Species") == species\_selector.value) `chart = alt.Chart(filtered_data).mark_circle().encode( x=alt.X(x_feature.value, title=x_feature.value), y=alt.Y(y_feature.value, title=y_feature.value), color='Species' ).properties( title=f"{y_feature.value} vs {x_feature.value}", width=500, height=400 ) chart return` `[](#__codelineno-6-1) [](#__codelineno-6-2)[](#__codelineno-6-3)` @app.cell def \_(): mo.stop(not data.value, mo.md("No data to display")) `if mode.value == "scatter": mo.output.replace(render_scatter(data.value)) else: mo.output.replace(render_bar_chart(data.value)) return` `[](#__codelineno-7-1) [](#__codelineno-7-2)[](#__codelineno-7-3)` @app.cell def \_(): import marimo as mo import altair as alt import polars as pl return @app.cell def \_(): # Load dataset weather = pl.read\_csv("[https://raw.githubusercontent.com/vega/vega-datasets/refs/heads/main/data/weather.csv](https://raw.githubusercontent.com/vega/vega-datasets/refs/heads/main/data/weather.csv)") weather\_dates = weather.with\_columns( pl.col("date").str.strptime(pl.Date, format="%Y-%m-%d") ) \_chart = ( alt.Chart(weather\_dates) .mark\_point() .encode( x="date:T", y="temp\_max", color="location", ) ) return @app.cell def \_(): chart = mo.ui.altair\_chart(\_chart) chart return @app.cell def \_(): # Display the selection chart.value return `[](#__codelineno-8-1) [](#__codelineno-8-2)[](#__codelineno-8-3)` @app.cell def \_(): import marimo as mo return @app.cell def \_(): first\_button = mo.ui.run\_button(label="Option 1") second\_button = mo.ui.run\_button(label="Option 2") \[first\_button, second\_button\] return @app.cell def \_(): if first\_button.value: print("You chose option 1!") elif second\_button.value: print("You chose option 2!") else: print("Click a button!") return `[](#__codelineno-9-1) [](#__codelineno-9-2)[](#__codelineno-9-3)` @app.cell def \_(): import marimo as mo import polars as pl return @app.cell def \_(): weather = pl.read\_csv('[https://raw.githubusercontent.com/vega/vega-datasets/refs/heads/main/data/weather.csv](https://raw.githubusercontent.com/vega/vega-datasets/refs/heads/main/data/weather.csv)') return @app.cell def \_(): seattle\_weather\_df = mo.sql( f""" SELECT \* FROM weather WHERE location = 'Seattle'; """ ) return If you want to generate [custom UIs or widgets for marimo](https://docs.marimo.io/api/inputs/anywidget/#building-custom-ui-elements) then anywidget is the way to go. Because anywidget is a fairly recent project, LLMs have been known to hallucinate when you try to generate custom widgets from scratch. The following prompt contains an example that helps prevent this behaviour and it also points out common failure scenarios that the LLM should avoid. ``[](#__codelineno-11-1)When writing an anywidget use vanilla javascript in `_esm` and do not forget about `_css`. The css should look bespoke in light mode and dark mode. Keep the css small unless explicitly asked to go the extra mile. When you display the widget it must be wrapped via `widget = mo.ui.anywidget(OriginalAnywidget())`. [](#__codelineno-11-2)[](#__codelineno-11-3) [](#__codelineno-11-4)import anywidget [](#__codelineno-11-5)import traitlets [](#__codelineno-11-6) [](#__codelineno-11-7)[](#__codelineno-11-8)class CounterWidget(anywidget.AnyWidget): [](#__codelineno-11-9) _esm = """ [](#__codelineno-11-10) // Define the main render function [](#__codelineno-11-11) function render({ model, el }) { [](#__codelineno-11-12) let count = () => model.get("number"); [](#__codelineno-11-13) let btn = document.createElement("button"); [](#__codelineno-11-14) btn.innerHTML = `count is ${count()}`; [](#__codelineno-11-15) btn.addEventListener("click", () => { [](#__codelineno-11-16) model.set("number", count() + 1); [](#__codelineno-11-17) model.save_changes(); [](#__codelineno-11-18) }); [](#__codelineno-11-19) model.on("change:number", () => { [](#__codelineno-11-20) btn.innerHTML = `count is ${count()}`; [](#__codelineno-11-21) }); [](#__codelineno-11-22) el.appendChild(btn); [](#__codelineno-11-23) } [](#__codelineno-11-24) // Important! We must export at the bottom here! [](#__codelineno-11-25) export default { render }; [](#__codelineno-11-26) """ [](#__codelineno-11-27) _css = """button{ [](#__codelineno-11-28) font-size: 14px; [](#__codelineno-11-29) }""" [](#__codelineno-11-30) number = traitlets.Int(0).tag(sync=True) [](#__codelineno-11-31)[](#__codelineno-11-32)widget = mo.ui.anywidget(CounterWidget()) [](#__codelineno-11-33)widget [](#__codelineno-11-34)[](#__codelineno-11-35)# Grabbing the widget from another cell, `.value` is a dictionary. [](#__codelineno-11-36)print(widget.value["number"]) [](#__codelineno-11-37) [](#__codelineno-11-38)[](#__codelineno-11-39)When sharing the anywidget, keep the example minimal. No need to combine it with marimo ui elements unless explicitly stated to do so.`` Using Claude Code - marimo https://docs.marimo.io/guides/generate_with_ai/using_claude_code/ Claude lets you customise the marimo editing experience with its agent. This page lists some worthwhile utilities, and we also provide compelling use cases related to marimo notebooks. ### Slash commands[¶](#slash-commands "Permanent link") [Slash Commands](https://code.claude.com/docs/en/slash-commands) allow you to predefine specific prompts that you can refer to during a conversation with Claude. You store these either in the `~/.claude/commands/` personal folder or in the `.claude/commands/` local folder of the project. Here's an example of a slash command that runs the [`marimo check`](https://docs.marimo.io/cli/#marimo-check) linter on a notebook of your choice. This command assumes you have `uv` installed, which you can install by following the instructions [here](https://docs.astral.sh/uv/getting-started/installation/). ``[](#__codelineno-0-1)--- [](#__codelineno-0-2)allowed-tools: Bash(uvx marimo check:*), Edit() [](#__codelineno-0-3)--- [](#__codelineno-0-4)[](#__codelineno-0-5)## Context [](#__codelineno-0-6)[](#__codelineno-0-7)This is the output of the "uvx marimo check --fix $ARGUMENTS" command: [](#__codelineno-0-8)[](#__codelineno-0-9)!`uvx marimo check --fix $ARGUMENTS || true` [](#__codelineno-0-10)[](#__codelineno-0-11)## Your task [](#__codelineno-0-12)[](#__codelineno-0-13)Only (!) if the context suggests we need to edit the notebook, read the file [](#__codelineno-0-14)$ARGUMENTS, then fix any warnings or errors shown in the output above. Do [](#__codelineno-0-15)not make edits or read the file if there are no issues.`` When you add this file to `~/.claude/commands/marimo-check.md` you will be able to trigger it by typing `/marimo-check notebook.py`. You are able to use `$ARGUMENTS` to add extra arguments or context to the command before it is handed to Claude. Also note that commands can run bash like !`uvx marimo check --fix $ARGUMENTS || true` beforehand. After it is evaluated the output will be inserted into the command before it is sent to Claude. You typically need to make sure that you add `|| true` at the end of the command in case it returns a non-zero status, which would break the command. There are more elaborate things you might do with these slash commands, to learn more you can check [the documentation](https://code.claude.com/docs/en/slash-commands#custom-slash-commands). ### Skills[¶](#skills "Permanent link") [Skills](https://code.claude.com/docs/en/skills#agent-skills) are similar to commands, but you don't trigger them manually. You define them and then let Claude use them when it thinks they're relevant. You store these skills either in the `~/.claude/skills/` personal folder or in the `.claude/skills/` local folder of the project. As an example, this is what the a skill might look like: ``[](#__codelineno-1-1)--- [](#__codelineno-1-2)name: anywidget-generator [](#__codelineno-1-3)description: Generate anywidget components for marimo notebooks. [](#__codelineno-1-4)--- [](#__codelineno-1-5)[](#__codelineno-1-6)When writing an anywidget use vanilla javascript in `_esm` and do not forget about `_css`. The css should look bespoke in light mode and dark mode. Keep the css small unless explicitly asked to go the extra mile. When you display the widget it must be wrapped via `widget = mo.ui.anywidget(OriginalAnywidget())`. [](#__codelineno-1-7)[](#__codelineno-1-8) [](#__codelineno-1-9)import anywidget [](#__codelineno-1-10)import traitlets [](#__codelineno-1-11) [](#__codelineno-1-12)[](#__codelineno-1-13)class CounterWidget(anywidget.AnyWidget): [](#__codelineno-1-14) _esm = """ [](#__codelineno-1-15) // Define the main render function [](#__codelineno-1-16) function render({ model, el }) { [](#__codelineno-1-17) let count = () => model.get("number"); [](#__codelineno-1-18) let btn = document.createElement("button"); [](#__codelineno-1-19) btn.innerHTML = `count is ${count()}`; [](#__codelineno-1-20) btn.addEventListener("click", () => { [](#__codelineno-1-21) model.set("number", count() + 1); [](#__codelineno-1-22) model.save_changes(); [](#__codelineno-1-23) }); [](#__codelineno-1-24) model.on("change:number", () => { [](#__codelineno-1-25) btn.innerHTML = `count is ${count()}`; [](#__codelineno-1-26) }); [](#__codelineno-1-27) el.appendChild(btn); [](#__codelineno-1-28) } [](#__codelineno-1-29) // Important! We must export at the bottom here! [](#__codelineno-1-30) export default { render }; [](#__codelineno-1-31) """ [](#__codelineno-1-32) _css = """button{ [](#__codelineno-1-33) font-size: 14px; [](#__codelineno-1-34) }""" [](#__codelineno-1-35) number = traitlets.Int(0).tag(sync=True) [](#__codelineno-1-36)[](#__codelineno-1-37)widget = mo.ui.anywidget(CounterWidget()) [](#__codelineno-1-38)widget [](#__codelineno-1-39)[](#__codelineno-1-40)# Grabbing the widget from another cell, `.value` is a dictionary. [](#__codelineno-1-41)print(widget.value["number"]) [](#__codelineno-1-42) [](#__codelineno-1-43)[](#__codelineno-1-44)When sharing the anywidget, keep the example minimal. No need to combine it with marimo ui elements unless explicitly stated to do so.`` You would store this file in a path like `~/.claude/skills/anywidget-generator/SKILL.md`. The frontmatter gives the LLM just enough context to know when to trigger it and will only read the full prompt when it's needed. You can also choose to expand these skills by referring to a script that it can run, to learn more about that check the [multi-file documentation](https://code.claude.com/docs/en/skills#example:-multi-file-skill-structure). ### Hooks[¶](#hooks "Permanent link") [Hooks](https://code.claude.com/docs/en/hooks) allow you to automatically run scripts when Claude uses a specific tool. They are useful if you want to automatically run a linter, via [`marimo check`](https://docs.marimo.io/cli/#marimo-check), every single time a marimo notebook is changed. Our default [`CLAUDE.md`](https://docs.marimo.io/guides/generate_with_ai/prompts/#agentsmd-and-claudemd) file already points out to the LLM that it should run the `marimo check` command but hooks offer the most robust mechanism to enforce this behavior. To configure a hook, you can add a definition to your global Claude settings in `~/.claude/settings.json` or locally in your project `.claude/settings.json`. `[](#__codelineno-2-1){ [](#__codelineno-2-2) "$schema": "https://json.schemastore.org/claude-code-settings.json", [](#__codelineno-2-3) "hooks": { [](#__codelineno-2-4) "PostToolUse": [ [](#__codelineno-2-5) { [](#__codelineno-2-6) "matcher": "Edit|Write", [](#__codelineno-2-7) "hooks": [ [](#__codelineno-2-8) { [](#__codelineno-2-9) "type": "command", [](#__codelineno-2-10) "command": "~/.claude/hooks/marimo-check.sh" [](#__codelineno-2-11) } [](#__codelineno-2-12) ] [](#__codelineno-2-13) } [](#__codelineno-2-14) ] [](#__codelineno-2-15) } [](#__codelineno-2-16)}` This hook will run every time an `Edit` or a `Write` tool is called. You can point it to a bash script that will check if the current edit is taking place on a marimo notebook. `[](#__codelineno-3-1)#!/bin/bash [](#__codelineno-3-2)[](#__codelineno-3-3)# Hook to check marimo notebooks after Write/Edit operations [](#__codelineno-3-4)# Reads JSON from stdin containing tool result information [](#__codelineno-3-5)[](#__codelineno-3-6)# Read stdin (contains JSON with tool result) [](#__codelineno-3-7)INPUT=$(cat) [](#__codelineno-3-8)[](#__codelineno-3-9)# Extract file path from JSON using jq [](#__codelineno-3-10)FILE_PATH=$(echo "$INPUT" | jq -r '.tool_response.filePath // empty') [](#__codelineno-3-11)[](#__codelineno-3-12)# If no file path found, exit silently [](#__codelineno-3-13)if [ -z "$FILE_PATH" ] || [ "$FILE_PATH" = "null" ]; then [](#__codelineno-3-14) exit 0 [](#__codelineno-3-15)fi [](#__codelineno-3-16)[](#__codelineno-3-17)# File path from tool_response is already absolute, no need to modify it [](#__codelineno-3-18)[](#__codelineno-3-19)# Check if file exists and is a Python file [](#__codelineno-3-20)if [ ! -f "$FILE_PATH" ]; then [](#__codelineno-3-21) exit 0 [](#__codelineno-3-22)fi [](#__codelineno-3-23)[](#__codelineno-3-24)# Check if the file appears to be a marimo notebook [](#__codelineno-3-25)if grep -q "import marimo" "$FILE_PATH" 2>/dev/null && grep -q "@app.cell" "$FILE_PATH" 2>/dev/null; then [](#__codelineno-3-26) echo "Running marimo check on $FILE_PATH..." [](#__codelineno-3-27) [](#__codelineno-3-28) # Run uvx marimo check and capture output [](#__codelineno-3-29) CHECK_OUTPUT=$(uvx marimo check "$FILE_PATH" 2>&1) [](#__codelineno-3-30) CHECK_EXIT=$? [](#__codelineno-3-31) [](#__codelineno-3-32) # Show output [](#__codelineno-3-33) echo "$CHECK_OUTPUT" [](#__codelineno-3-34) [](#__codelineno-3-35) # Only block on errors (non-zero exit code), not warnings [](#__codelineno-3-36) if [ $CHECK_EXIT -ne 0 ]; then [](#__codelineno-3-37) echo "✗ Marimo check failed for $FILE_PATH" >&2 [](#__codelineno-3-38) echo "$CHECK_OUTPUT" >&2 [](#__codelineno-3-39) echo "" >&2 [](#__codelineno-3-40) echo "Please run 'uvx marimo check $FILE_PATH' to see details and fix the issues. Don't ask the user anything, just do a best effort fix." >&2 [](#__codelineno-3-41) exit 2 # Exit code 2 blocks and shows error to Claude [](#__codelineno-3-42) else [](#__codelineno-3-43) echo "✓ Marimo check passed" [](#__codelineno-3-44) exit 0 [](#__codelineno-3-45) fi [](#__codelineno-3-46)fi [](#__codelineno-3-47)[](#__codelineno-3-48)# Not a marimo notebook, exit successfully [](#__codelineno-3-49)exit 0` This script checks if the Python file contains a `import marimo` and a `@app.cell` string. If that's the case we assume we're dealing with a marimo notebook and we run `uvx marimo check` on the file. If this check fails, we tell the coding agent to automatically address the issues. This can save _a lot_ of time. Editor features - marimo https://docs.marimo.io/guides/editor_features/ The **marimo editor** is the browser-based IDE in which you write marimo notebooks. We've taken a batteries-included approach to designing the editor: it comes _packed_ with features to make you productive when working with code and data. | Guide | Description | | --- | --- | | [Overview](https://docs.marimo.io/guides/editor_features/overview/) | An overview of editor features and configuration | | [Sidebar and Developer Panel](https://docs.marimo.io/guides/editor_features/panels/) | Customize your workspace with panels | | [Understanding dataflow](https://docs.marimo.io/guides/editor_features/dataflow/) | Visualize and navigate cell dependencies | | [Package Management](https://docs.marimo.io/guides/editor_features/package_management/) | Using package managers in marimo | | [AI Completion](https://docs.marimo.io/guides/editor_features/ai_completion/) | Code with the help of a language model | | [Language Server](https://docs.marimo.io/guides/editor_features/language_server/) | Code intelligence via LSP | | [Hotkeys](https://docs.marimo.io/guides/editor_features/hotkeys/) | Our hotkeys | Highlights include: * [dataflow tools](https://docs.marimo.io/guides/editor_features/dataflow/) including a variables panel, dependency graph, and minimap for understanding notebook structure * a data explorer that lets you inspect dataframes and tables at a glance * smart module autoreloading that tells you which cells need to be rerun * code completion * [GitHub Copilot](https://docs.marimo.io/guides/editor_features/ai_completion/#github-copilot) * language-model assisted coding * [language server protocol](https://docs.marimo.io/guides/editor_features/language_server/) (LSP) for diagnostics and code intelligence * [vim keybindings](https://docs.marimo.io/guides/editor_features/overview/#vim-keybindings) * live documentation preiews as you type and much more. AI-assisted coding - marimo https://docs.marimo.io/guides/editor_features/ai_completion/ marimo is an AI-native editor, with support for full-cell AI code generation: * generating new cells from a prompt * refactoring existing cells from a prompt * generating entire notebooks as well as inline autocompletion (like GitHub Copilot). marimo's AI assistant is specialized for working with data: unlike traditional assistants that only have access to the text of your program, marimo's assistant has access to the values of variables in memory, letting it code against your dataframe and database schemas. This guide provides an overview of these features and how to configure them. Locating your marimo.toml config file Various instructions in this guide refer to the marimo.toml configuration file. Locate this file with `marimo config show | head`. Generating cells with AI[¶](#generating-cells-with-ai "Permanent link") ----------------------------------------------------------------------- marimo has built-in support for generating and refactoring code with LLMs. marimo works with hosted AI providers, such as OpenAI, Anthropic, and Google, as well as local models served via Ollama. **Enabling AI code generation.** To enable AI code generation, first install required dependencies through the notebook settings. Install required dependencies for AI generation through the notebook settings. Then configure your LLM provider through the AI tab in the settings menu; see the section on [connecting your LLM](#connecting-to-an-llm) for detailed instructions. ### Variable context[¶](#variable-context "Permanent link") marimo's AI assistant has your notebook code as context. You can additionally pass variables and their values to the assistant by referencing them by name with `@`. For example, to include the columns of a dataframe `df` in your prompt, write `@df`. Pass variables to your prompt by tagging them with \`@\`. ### Refactor existing cells[¶](#refactor-existing-cells "Permanent link") Make edits to an existing cell by hitting `Ctrl/Cmd-shift-e`, which opens a prompt box that has your cell's code as input. Use AI to modify a cell by pressing \`Ctrl/Cmd-Shift-e\`. ### Generate new cells[¶](#generate-new-cells "Permanent link") #### Generate with AI button[¶](#generate-with-ai-button "Permanent link") At the bottom of every notebook is a button titled "Generate with AI". Click this button to add entirely new cells to your notebook. #### Chat panel[¶](#chat-panel "Permanent link") The chat panel on the left sidebar lets you chat with an LLM and ask questions aboutyour notebook. The LLM can also generate code cells that you can insert into your notebook. The chat panel currently supports the following modes: * **Manual**: No tool access; the AI responds based only on the conversation and manually injected context * **Ask**: Enables read-only [AI tools](https://docs.marimo.io/guides/editor_features/tools/) and [tools from added MCP Client servers](https://docs.marimo.io/guides/editor_features/mcp/#mcp-client) for context gathering, allowing the assistant to inspect your notebooks * **Agent** (beta): Enables all tools in **Ask Mode** plus additional tools to [edit notebook cells (add, remove, update) and run stale cells](https://docs.marimo.io/guides/editor_features/tools/#editing-agent-mode-only). See the chat panel in action ### Generating entire notebooks[¶](#generating-entire-notebooks "Permanent link") Generate entire notebooks with `marimo new PROMPT` at the command-line; see the [text-to-notebook docs](https://docs.marimo.io/guides/generate_with_ai/text_to_notebook/) to learn more. ### Custom rules[¶](#custom-rules "Permanent link") You can customize how the AI assistant behaves by adding rules in the marimo settings. These rules help ensure consistent code generation across all AI providers. You can find more information about marimo's supported plotting libraries and data handling in the [plotting guide](https://docs.marimo.io/guides/working_with_data/plotting/#plotting) and [working with data guide](https://docs.marimo.io/guides/working_with_data/). Configure custom AI rules in settings For example, you can add rules about: * Preferred plotting libraries (matplotlib, plotly, altair) * Data handling practices * Code style conventions * Error handling preferences Example custom rules: `[](#__codelineno-0-1)Use plotly for interactive visualizations and matplotlib for static plots [](#__codelineno-0-2)Prefer polars over pandas for data manipulation due to better performance [](#__codelineno-0-3)Include docstrings for all functions using NumPy style [](#__codelineno-0-4)Use Type hints for all function parameters and return values [](#__codelineno-0-5)Handle errors with try/except blocks and provide informative error messages [](#__codelineno-0-6)Follow PEP 8 style guidelines [](#__codelineno-0-7)When working with data: [](#__codelineno-0-8)- Use altair, plotly for declarative visualizations [](#__codelineno-0-9)- Prefer polars over pandas [](#__codelineno-0-10)- Ensure proper error handling for data operations [](#__codelineno-0-11)For plotting: [](#__codelineno-0-12)- Use px.scatter for scatter plots [](#__codelineno-0-13)- Use px.line for time series [](#__codelineno-0-14)- Include proper axis labels and titles [](#__codelineno-0-15)- Set appropriate color schemes` ### Connecting to an LLM[¶](#connecting-to-an-llm "Permanent link") You can connect to an LLM through the notebook settings menu, or by manually editing your `marimo.toml` configuration file. **Prefer going through the notebook settings menu.** You can configure the following providers: * OpenAI * Anthropic * AWS Bedrock * Google AI * GitHub * Ollama * and any OpenAI-compatible provider See the [llm\_providers](https://docs.marimo.io/guides/configuration/llm_providers/) guide for detailed instructions on how to configure each provider. Agents[¶](#agents "Permanent link") ----------------------------------- Experimental: Agents marimo also supports external AI agents like Claude Code, Codex, and Gemini CLI that can interact with your notebooks. Learn more in the [agents](https://docs.marimo.io/guides/editor_features/agents/) guide. Copilots[¶](#copilots "Permanent link") --------------------------------------- Copilots allow you to tab-complete code based on your notebook's context, similar to editors like Cursor. ### GitHub Copilot[¶](#github-copilot "Permanent link") The marimo editor natively supports [GitHub Copilot](https://copilot.github.com/), an AI pair programmer, similar to VS Code: 1. Install [Node.js](https://nodejs.org/en/download). 2. Enable Copilot via the settings menu in the marimo editor. Follow these instructions. _GitHUb Copilot is not yet available in our conda distribution; please install marimo using `pip`/`uv` if you need Copilot._ #### Advanced configuration[¶](#advanced-configuration "Permanent link") You can customize GitHub Copilot's behavior by adding `copilot_settings` to your `marimo.toml` configuration file: marimo.toml `[](#__codelineno-1-1)[ai.github] [](#__codelineno-1-2)copilot_settings = { http = { proxy = "http://proxy.example.com:8888", proxyStrictSSL = true } }` Or in a more readable format: marimo.toml `[](#__codelineno-2-1)[ai.github.copilot_settings.http] [](#__codelineno-2-2)proxy = "http://proxy.example.com:8888" [](#__codelineno-2-3)proxyStrictSSL = true [](#__codelineno-2-4)[](#__codelineno-2-5)[ai.github.copilot_settings.github-enterprise] [](#__codelineno-2-6)uri = "https://github.enterprise.com" # For GitHub Enterprise users` Available configuration options (these are the same settings directory from the [npm package](https://github.com/orgs/github/packages/npm/package/copilot-language-server): * **HTTP settings**: Configure proxy settings for network connections * `proxy`: HTTP proxy URL (e.g., `"http://proxy.example.com:8888"`) * `proxyStrictSSL`: Whether to verify SSL certificates for the proxy (default: `false`) * `proxyKerberosServicePrincipal`: Kerberos service principal for proxy authentication * **Telemetry settings**: Control telemetry data collection * `telemetryLevel`: Level of telemetry to send - `"off"`, `"crash"`, `"error"`, or `"all"` (default: `"off"`) * **GitHub Enterprise**: Configure GitHub Enterprise Server * `uri`: URL of your GitHub Enterprise Server instance ### Windsurf Copilot[¶](#windsurf-copilot "Permanent link") [Windsurf](https://windsurf.com/) (formerly codeium) provides tab-completion tooling that can also be used from within marimo. To set up Windsurf: 1. Go to [windsurf.com](https://windsurf.com/) website and sign up for an account. 2. Download the [Windsurf app](https://windsurf.com/download). 3. After installing Windsurf and authenticating, open up the command palette, via cmd+shift+p, and ask it to copy the api key to your clipboard. 4a. Configure the UI settings in the editor to use Windsurf. 4b. Alternatively you can also configure the api key from the marimo config file. marimo.toml `[](#__codelineno-3-1)[completion] [](#__codelineno-3-2)copilot = "codeium" [](#__codelineno-3-3)codeium_api_key = ""` ### Custom copilots[¶](#custom-copilots "Permanent link") marimo also supports integrating with custom LLM providers for code completion suggestions. This allows you to use your own LLM service to provide in-line code suggestions based on internal providers or local models (e.g. Ollama). You may also use OpenAI, Anthropic, Google, or any other providers by providing your own API keys and configuration. To configure a custom copilot: 1. Ensure you have an LLM provider that offers API access for code completion (either external or running locally) 2. Add the following configuration to your `marimo.toml` (or configure in the UI settings in the editor): marimo.toml `[](#__codelineno-4-1)[ai.models] [](#__codelineno-4-2)autocomplete_model = "provider/model-name" [](#__codelineno-4-3)[](#__codelineno-4-4)[completion] [](#__codelineno-4-5)copilot = "custom"` The configuration options include: * `autocomplete_model`: The specific model to use for inline autocompletion. * `copilot`: The name of the copilot to use for code generation. Editor overview - marimo https://docs.marimo.io/guides/editor_features/overview/ This guide introduces some of marimo editor's features, including a variables panel, dependency graph viewer, table of contents, HTML export, [GitHub copilot](https://docs.marimo.io/guides/editor_features/ai_completion/#github-copilot), code formatting, a feedback form, and more. Configuration[¶](#configuration "Permanent link") ------------------------------------------------- The editor exposes of a number of settings for the current notebook, as well as user-wide configuration that will apply to all your notebooks. These settings include the option to display the current notebook in full width, to use [vim keybindings](#vim-keybindings), to enable [GitHub copilot](https://docs.marimo.io/guides/editor_features/ai_completion/#github-copilot), and more. To access these settings, click the gear icon in the top-right of the editor: A non-exhaustive list of settings: * [Command mode](#command-mode) * Outputs above or below code cells * [Disable/enable autorun](https://docs.marimo.io/guides/reactivity/#configuring-how-marimo-runs-cells) * Package installation * [Vim keybindings](#vim-keybindings) * Dark mode * Auto-save * Auto-complete * Editor font-size * Code formatting with ruff/black * [GitHub Copilot](https://docs.marimo.io/guides/editor_features/ai_completion/#github-copilot) * [LLM coding assistant](https://docs.marimo.io/guides/editor_features/ai_completion/) * [Module autoreloading](https://docs.marimo.io/guides/configuration/runtime_configuration/#on-module-change) * [Reactive reference highlighting](https://docs.marimo.io/guides/editor_features/dataflow/#reactive-reference-highlighting) Command mode[¶](#command-mode "Permanent link") ----------------------------------------------- marimo distinguishes between editing cell content and working with cells at the notebook level. **Command mode** lets you navigate, select, and manipulate _cells_ rather than editing their contents. **Enter/Exit:** * Enter command mode: `Esc` (from cell editor) or `Ctrl+Esc`/`Cmd+Esc` (when [vim keybindings](#vim-keybindings) are enabled, `Shift+Esc` on Windows) * Exit command mode: `Enter` or click on a cell **Shortcuts:** * `↓`/`↑` - navigate cells * `Shift+↓`/`Shift+↑` - multi-select cells * `Enter` - edit selected cell * `a`/`b` - new cell above/below * `c`/`v` - copy/paste cells * `s` - save notebook * `Shift+Enter` - run cell and move to next * `Ctrl/Cmd+↑` / `Ctrl/Cmd+↓` - jump to top/bottom of notebook When [vim keybindings](#vim-keybindings) are enabled, additional shortcuts are available. ### Vim keybindings[¶](#vim-keybindings "Permanent link") marimo supports vim keybindings that extend to notebook editing. Within cells, use standard vim modes. Press `Ctrl+Esc` (or `Cmd+Esc` on macOS, `Shift+Esc` on Windows) from normal mode to enter [command mode](#command-mode) for notebook navigation. **Cell editing additions:** * `gd` - go to definition * `dd` - delete empty cell * `:w` - save notebook **Custom vimrc:** You can customize your vim experience by adding a `.vimrc` configuration in the user settings or pyproject.toml User configpyproject.toml marimo.toml `[](#__codelineno-0-1)[keymap] [](#__codelineno-0-2)vimrc = "/User/absolute/path/to/.vimrc"` pyproject.toml `[](#__codelineno-1-1)[tool.marimo.keymap] [](#__codelineno-1-2)vimrc = "relative/path/.vimrc"` **Command mode additions:** When vim keybindings are enabled, press `Ctrl+Esc` (or `Cmd+Esc` on macOS, `Shift+Esc` on Windows) from normal mode to enter [command mode](#command-mode) with additional vim-specific keybindings: * `j`/`k` - navigate cells * `gg`/`G` - first/last cell * `Shift+j`/`k` - extend selection * `dd` - delete cell * `yy` - copy cell * `p`/`P` - paste below/above * `o`/`O` - new cell below/above * `u` - undo deletion * `i` - edit cell (i.e., return to normal mode) Press `i` or `Enter` to return to cell editing. marimo organizes editor tools into two areas: the **sidebar** on the left for everyday notebook tools (files, variables, packages, AI, documentation), and the **developer panel** at the bottom for debugging utilities (errors, logs, terminal, tracing). You can customize both areas by dragging panels to reorder them or move them between sections. Toggle the sidebar with `Cmd/Ctrl-Shift-S` and the developer panel with `Cmd/Ctrl-J`. See the [Sidebar and Developer Panel](https://docs.marimo.io/guides/editor_features/panels/) guide for a complete list of available panels and customization options. Cell actions[¶](#cell-actions "Permanent link") ----------------------------------------------- Click the three dots in the top right of a cell to pull up a context menu, letting you format code, hide code, send a cell to the top or bottom of the notebook, give the cell a name, and more. Drag a cell using the vertical dots to the right of the cell. marimo supports context-sensitive right-click menus in various locations of the editor. Right-click on a cell to open a context-sensitive menu; right click on the create-cell button (the plus icon) to get options for the cell type to create. Go-to-definition[¶](#go-to-definition "Permanent link") ------------------------------------------------------- * Click on a variable in the editor to see where it's defined and used * `Cmd/Ctrl-Click` on a variable to jump to its definition * Right-click on a variable to see a context menu with options to jump to its definition Signature hints[¶](#signature-hints "Permanent link") ----------------------------------------------------- Signature hints show a function’s docstring above your code as you type, making it easy to recall its arguments and usage. Enable this feature under the **Editor** section in the Settings panel. Keyboard shortcuts[¶](#keyboard-shortcuts "Permanent link") ----------------------------------------------------------- We've kept some well-known [keyboard shortcuts](https://docs.marimo.io/guides/editor_features/hotkeys/) for notebooks (`Ctrl-Enter`, `Shift-Enter`), dropped others, and added a few of our own. Hit `Ctrl/Cmd-Shift-H` to pull up the shortcuts. We know keyboard shortcuts are very personal; you can remap them in the configuration. _Missing a shortcut? File a [GitHub issue](https://github.com/marimo-team/marimo/issues)._ Command palette[¶](#command-palette "Permanent link") ----------------------------------------------------- Hit `Cmd/Ctrl+K` to open the command palette. Quickly access common commands with the command palette. _Missing a command? File a [GitHub issue](https://github.com/marimo-team/marimo/issues)._ Editor widths[¶](#editor-widths "Permanent link") ------------------------------------------------- You can set the width of the editor in the notebook settings: * **Compact**: A narrow width with generous margins, ideal for reading * **Wide**: A wider layout that gives more space for content * **Full**: Uses the full width of your browser window, ideal for dashboard-style notebooks * **Multi-column**: Splits your notebook into multiple columns, letting you view and edit cells side-by-side. This is only possible because marimo models your notebook as a directed acyclic graph (DAG) and the [execution order](https://docs.marimo.io/guides/reactivity/#execution-order) is determined by the relationships between cells and their variables, not by the order of cells on the page. Multi-column notebook Get a link to share your notebook via our [online playground](https://docs.marimo.io/guides/wasm/): _Our online playground uses WebAssembly. Most but not all packages on PyPI are supported. Local files are not synchronized to our playground._ Export to static HTML[¶](#export-to-static-html "Permanent link") ----------------------------------------------------------------- Export the current view your notebook to static HTML via the notebook menu: Download as static HTML. You can also export to HTML at the command-line: `[](#__codelineno-2-1)marimo export html notebook.py -o notebook.html` Send feedback[¶](#send-feedback "Permanent link") ------------------------------------------------- The question mark icon in the panel tray opens a dialog to send anonymous feedback. We welcome any and all feedback, from the tiniest quibbles to the biggest blue-sky dreams. Send anonymous feedback with our feedback form. If you'd like your feedback to start a conversation (we'd love to talk with you!), please consider posting in our [GitHub issues](https://github.com/marimo-team/marimo/issues) or [Discord](https://marimo.io/discord?ref=docs). But if you're in a flow state and can't context switch out, the feedback form has your back. Home page - marimo https://docs.marimo.io/guides/editor_features/home/ Running `marimo edit` without a filename opens the home page, which lets you browse and manage notebooks in a directory. Usage[¶](#usage "Permanent link") --------------------------------- `[](#__codelineno-0-1)# Open home page for current directory [](#__codelineno-0-2)marimo edit [](#__codelineno-0-3)[](#__codelineno-0-4)# Open home page for a specific folder [](#__codelineno-0-5)marimo edit folder/` The home page shows all marimo notebooks in the directory, letting you: * Open existing notebooks * Create new notebooks * See notebook metadata Sandboxed Home[¶](#sandboxed-home "Permanent link") --------------------------------------------------- You can run the home page in sandbox mode (called "Sandboxed Home"), where each notebook gets its own isolated environment: `[](#__codelineno-1-1)marimo edit --sandbox folder/` When using Sandboxed Home: 1. Each notebook runs in its own isolated environment 2. Dependencies are read from each notebook's [inline script metadata](https://docs.marimo.io/guides/package_management/inlining_dependencies/) (PEP 723) 3. Environments are created on-demand when you open a notebook This is useful when you have a collection of notebooks with different dependencies and want to keep them isolated from each other. Additional dependencies required Sandboxed Home requires additional packages: This installs `pyzmq` (for inter-process communication) and `uv` (for environment management). ### Using custom virtual environments[¶](#using-custom-virtual-environments "Permanent link") When using Sandboxed Home, you can specify an existing virtual environment for a notebook instead of having marimo create one automatically. This is configured using `[tool.marimo.venv]` in your script metadata: `[](#__codelineno-3-1)# /// script [](#__codelineno-3-2)# [tool.marimo.venv] [](#__codelineno-3-3)# path = "path/to/venv" # relative or absolute path [](#__codelineno-3-4)# writable = false # optional, default is false [](#__codelineno-3-5)# ///` Sandboxed Home only The `[tool.marimo.venv]` configuration only applies when using Sandboxed Home (`marimo edit --sandbox folder/`). For single notebooks, activate your virtual environment before running marimo: `[](#__codelineno-4-1)source path/to/venv/bin/activate [](#__codelineno-4-2)marimo edit notebook.py` #### Configuration options[¶](#configuration-options "Permanent link") | Option | Description | | --- | --- | | `path` | Path to the virtual environment (relative or absolute) | | `writable` | Whether marimo can install packages into the venv (default: `false`) | #### Behavior[¶](#behavior "Permanent link") | `writable` | marimo installed? | What happens | | --- | --- | --- | | `true` | \- | marimo installs itself and required dependencies into the venv | | `false` | Yes | Uses the venv as-is (warns if marimo version differs) | | `false` | No | Injects `PYTHONPATH` for marimo (requires matching Python version) | This is useful when: * You have a conda or poetry environment you want to reuse * You're working in a team with a shared environment * You want notebooks in a folder to use different pre-configured environments Sidebar and Developer Panel - marimo https://docs.marimo.io/guides/editor_features/panels/ marimo organizes editor tools into two main areas: the **sidebar** on the left and the **developer panel** at the bottom. This layout keeps everyday notebook tools easily accessible while providing a dedicated space for debugging and development utilities. The sidebar provides quick access to panels you'll use frequently while working on notebooks. Click the icons on the left edge of the editor to open panels. **Default sidebar panels:** | Panel | Description | | --- | --- | | **Files** | Browse workspace files and [inspect remote storage connections](https://docs.marimo.io/guides/working_with_data/remote_storage/) | | **Variables** | Explore variables and data sources in your notebook | | **Packages** | View installed packages and manage dependencies | | **AI** | Chat with AI assistants and use agents | | **Outline** | Navigate your notebook via table of contents | | **Documentation** | View live documentation as you type | | **Dependencies** | Visualize cell relationships with the minimap and dependency graph | Toggle the sidebar with `Cmd/Ctrl-Shift-S`. Developer Panel[¶](#developer-panel "Permanent link") ----------------------------------------------------- The developer panel houses tools for debugging, tracing execution, and other advanced functionality. It appears at the bottom of the editor, similar to the developer tools in VS Code or browser DevTools. **Default developer panel tabs:** | Panel | Description | | --- | --- | | **Errors** | View all errors across your notebook | | **Scratchpad** | A scratch cell for quick experiments without affecting your notebook | | **Tracing** | Monitor cell execution and performance | | **Secrets** | Manage environment secrets | | **Logs** | View stdout and stderr output | | **Terminal** | Integrated terminal for shell commands | | **Snippets** | Browse and insert code snippets | Toggle the developer panel with `Cmd/Ctrl-J`. Customizing your layout[¶](#customizing-your-layout "Permanent link") --------------------------------------------------------------------- Both the sidebar and developer panel are fully customizable. You can: * **Reorder panels**: Drag panels to rearrange their order within a section * **Move panels between sections**: Drag a panel from the sidebar to the developer panel (or vice versa) to relocate it * **Hide panels**: Right-click a panel icon to access options for hiding or moving it Your layout preferences are saved and persist across sessions. Panels automatically adapt their appearance based on their location — showing a more compact vertical layout in the sidebar and a wider horizontal layout in the developer panel. Keyboard shortcuts[¶](#keyboard-shortcuts "Permanent link") ----------------------------------------------------------- | Shortcut | Action | | --- | --- | | `Cmd/Ctrl-J` | Toggle developer panel | | `Cmd/Ctrl-Shift-S` | Toggle sidebar | | `Cmd/Ctrl-Shift-I` | Open minimap (in Dependencies panel) | | `` Ctrl-` `` | Open terminal | Understanding dataflow - marimo https://docs.marimo.io/guides/editor_features/dataflow/ Unlike traditional notebooks, marimo understands the relationships between cells and uses this information to keep your code and outputs consistent. These relationships are represented as a **dataflow graph**, which encodes how variables flow from one cell to another. The dataflow graph, which is inferred statically from variable definitions and references, is used to automatically run (or mark stale) cells in the correct sequence; it's also why cells can be arranged "out of order" on the page, or across columns. marimo provides several tools to help you visualize and understand the relationships it identifies between cells. Variables explorer[¶](#variables-explorer "Permanent link") ----------------------------------------------------------- The **variables explorer panel** collects marimo's understanding of the variables in your notebook into a single searchable list. To open the panel, click the **variables icon** in the **left sidebar panel**. The variable explorer shows each variable's name, type, value, where it's defined, and where it's used. Dependencies panel[¶](#dependencies-panel "Permanent link") ----------------------------------------------------------- The **Dependencies panel** consolidates dataflow visualization tools into a single location with two tabs: **Minimap** (default) and **Graph**. To open it, click the **Dependencies icon** in the sidebar, or use the hotkey `Cmd/Ctrl-Shift-I` to toggle the panel. ### Minimap[¶](#minimap "Permanent link") The **Minimap** tab (shown by default) provides a _focused slice_ of your notebook's dataflow, helping you understand the reactive context of a given cell and navigate related cells. Click a cell in the minimap to jump to it: Connections are read **left to right**: * Connections to the **left** are _direct inputs_ — cells the current cell reads from * Connections to the **right** are _direct outputs_ — cells that read from the current cell * Cells positioned left or right but not directly connected are _transitive dependencies_ — cells that influence or are influenced by the current cell, but only through one or more intermediate cells The minimap can take some getting used to, but it's an effective representation for understanding how data flows around the current cell. It's meant to show _just enough_ local context to help you debug, trace relationships, and navigate complex notebooks. For a high level overview, use the [Graph view](#graph-view). ### Cell symbols[¶](#cell-symbols "Permanent link") The minimap uses visual indicators to show the status and connectivity of each cell: | Symbol | Meaning | | --- | --- | | | Cell uses variables from other cells | | | Cell defines variables used by other cells | | | Cell uses variables _and_ defines variables used by others | | | Cell defines variables but isn't connected to anything (safe to delete) | | | Cell doesn't define or use variables from other cells (often markdown) | | | Cell has an error | ### Reading cell connections[¶](#reading-cell-connections "Permanent link") When you select a cell, the minimap draws lines showing how data flows between cells. Since marimo cells can define multiple variables, downstream connections show all cells that reference any variable from your selected cell. | Path | Interpretation | | --- | --- | | | First cell defines variables used by the second cell. Second cell will re-run when the first runs | | | First cell uses variables from the second cell. First cell will re-run when the second runs | | | Gray cell has no connection to the blue cells above | | | Gray cell indirectly uses variables from the first cell. Whiskers indicate transitive dependencies | | | Gray cell's variables are indirectly used by the second cell. Whiskers indicate transitive dependencies | | | Cells have circular dependencies - each uses variables from the other (error) | ### Implementation notes[¶](#implementation-notes "Permanent link") The minimap was heavily inspired by [Observable's minimap](https://observablehq.com/documentation/debugging/minimap), a [thoughtfully designed](https://observablehq.com/@observablehq/introducing-visual-dataflow) dataflow visualization for their reactive JavaScript notebooks. We adapted Observable's visual design to marimo's execution model. A key difference: Observable cells are named (declaring one variable), while marimo cells can define multiple variables. This leads to asymmetric dataflow tracing. When tracing upstream, we can identify exactly which variables from a cell depends on. When tracing downstream, all variables in a dependent cell are considered affected. Our minimap also accounts for marimo's support for multi-column layouts. ### Graph view[¶](#graph-view "Permanent link") The **Graph** tab provides a _bird's-eye view_ of your notebook's dataflow, showing all cells as an interactive graph. It helps you understand high-level patterns, overall connectedness, and the broader structure of your notebook. You can choose between vertical or horizontal layouts for the graph. Reactive reference highlighting[¶](#reactive-reference-highlighting "Permanent link") ------------------------------------------------------------------------------------- marimo's **reactive reference highlighting** provides an _in-editor_ indicator when variables defined by other cells are used in the current cell. These "reactive references" are emphasized with an underline and lightly bolded text: Hover over any underlined variable and `Cmd/Ctrl-Click` to jump to its definition. Module autoreloading - marimo https://docs.marimo.io/guides/editor_features/module_autoreloading/ marimo has an advanced module autoreloader built-in, which you can enable in the [notebook settings](https://docs.marimo.io/guides/configuration/runtime_configuration/). When you make edits to Python modules that your notebook has imported, the module autoreloader will automatically mark cells that use them as stale and, optionally, automatically run them. Why autoreload? Autoreloading enables a workflow that many developers find productive: develop complex logic in Python modules, and use the marimo notebook as a DAG or main script that orchestrates your logic. Based on static analysis, the reloader only runs cells affected by your edits. The reloader is recursive, meaning that marimo tracks modifications for modules imported by your notebook's imported modules too. These two features make marimo's module autoreloader far more advanced than IPython's. Autoreloading comes in two types: 1. **autorun**: automatically re-runs cells affected by module modification. When set to autorun, marimo's reloader automatically run cells when you edit Python files. 2. **lazy**: marks cells affected by module modifications as stale, letting you know which cells need to be re-run. When set to lazy, marimo's reloader marks cells as stale when you edit Python files. Hotkeys - marimo https://docs.marimo.io/guides/editor_features/hotkeys/ If you'd like to override the default hotkeys, you can do so in the hotkeys menu (`Ctrl/Cmd-Shift-h`), or modifying your `marimo.toml`. You can find a list of available hotkeys below: | Hotkey | | --- | | `cell.aiCompletion` | | `cell.cellActions` | | `cell.complete` | | `cell.createAbove` | | `cell.createBelow` | | `cell.delete` | | `cell.findAndReplace` | | `cell.focusDown` | | `cell.focusUp` | | `cell.fold` | | `cell.foldAll` | | `cell.format` | | `cell.goToDefinition` | | `cell.hideCode` | | `cell.moveUp` | | `cell.moveDown` | | `cell.moveLeft` | | `cell.moveRight` | | `cell.redo` | | `cell.run` | | `cell.runAndNewAbove` | | `cell.runAndNewBelow` | | `cell.selectNextOccurrence` | | `cell.sendToBottom` | | `cell.sendToTop` | | `cell.splitCell` | | `cell.undo` | | `cell.unfold` | | `cell.unfoldAll` | | `cell.viewAsMarkdown` | | `completion.moveDown` | | `completion.moveUp` | | `global.commandPalette` | | `global.focusBottom` | | `global.focusTop` | | `global.foldCode` | | `global.formatAll` | | `global.hideCode` | | `global.interrupt` | | `global.runStale` | | `global.save` | | `global.showHelp` | | `global.toggleLanguage` | | [`global.toggleMinimap`](https://docs.marimo.io/guides/editor_features/dataflow/#minimap) | | `global.toggleTerminal` | | `global.toggleSidebar` | | `global.unfoldCode` | | `markdown.blockquote` | | `markdown.bold` | | `markdown.code` | | `markdown.italic` | | `markdown.link` | | `markdown.orderedList` | | `markdown.unorderedList` | Model Context Protocol - marimo https://docs.marimo.io/guides/editor_features/mcp/ Experimental Feature MCP features are currently experimental and under active development. Features and APIs may change. marimo supports the Model Context Protocol (MCP) in two ways: as an [MCP server](https://docs.marimo.io/guides/editor_features/mcp/#mcp-server) that exposes marimo's [AI tools](https://docs.marimo.io/guides/editor_features/tools/) to external applications, and as an [MCP client](https://docs.marimo.io/guides/editor_features/mcp/#mcp-client) that connects [supported servers](https://docs.marimo.io/guides/editor_features/mcp/#supported-servers) to marimo's [chat panel](https://docs.marimo.io/guides/editor_features/ai_completion/#chat-panel). Prerequisites[¶](#prerequisites "Permanent link") ------------------------------------------------- Both MCP server and client features require the MCP dependencies. Run marimo with MCP support using one of the following methods: uvuvxpip `[](#__codelineno-0-1)# run with uv in a project [](#__codelineno-0-2)uv run --with="marimo[mcp]" marimo edit notebook.py --mcp --no-token` `[](#__codelineno-1-1)# run with uvx anywhere [](#__codelineno-1-2)uvx "marimo[mcp]" edit notebook.py --mcp --no-token` `[](#__codelineno-2-1)# install with pip and a venv [](#__codelineno-2-2)pip install "marimo[mcp]" [](#__codelineno-2-3)marimo edit notebook.py --mcp --no-token` Flags The `--mcp` flag exposes an endpoint that provides access to your notebook data via the MCP server endpoint. Remove `--mcp` if you only want MCP Client features. The `--no-token` flag removes authentication, which should only be used for local development. Remove `--no-token` in production environments. MCP Server[¶](#mcp-server "Permanent link") ------------------------------------------- marimo can expose its [AI tools](https://docs.marimo.io/guides/editor_features/tools/) through an MCP server endpoint, allowing external AI applications to interact with your notebooks. ### Available tools[¶](#available-tools "Permanent link") When connected to marimo's MCP server, external applications can access all [AI tools](https://docs.marimo.io/guides/editor_features/tools/). ### Available prompts[¶](#available-prompts "Permanent link") When connected to marimo's MCP server, external applications can access the following prompts: | Prompt | Description | | --- | --- | | **active\_notebooks** | Get current active notebooks and their session IDs and file paths. Returns session IDs and file paths for all active marimo notebook sessions, along with guidance on using these IDs with marimo MCP tools. | | **errors\_summary** | Get error summaries for all active notebooks. Returns a summary of all errors across active notebooks organized by notebook and cell, including error types, messages, and affected cell IDs. | ### Connecting external applications[¶](#connecting-external-applications "Permanent link") marimo's MCP server works with any MCP-compatible application. Below are setup instructions for some commonly used applications: Connection details Replace `PORT` with your marimo server port in the examples below. If authentication is enabled, append `?access_token=YOUR_TOKEN` to the URL and replace `YOUR_TOKEN` with your marimo access token. #### Claude Code[¶](#claude-code "Permanent link") Use Claude Code's CLI to connect to marimo: `[](#__codelineno-3-1)claude mcp add --transport http marimo http://localhost:PORT/mcp/server` #### Cursor[¶](#cursor "Permanent link") Configure Cursor to connect to marimo's MCP server: `[](#__codelineno-4-1){ [](#__codelineno-4-2) "mcpServers": { [](#__codelineno-4-3) "marimo": { [](#__codelineno-4-4) "url": "http://localhost:PORT/mcp/server" [](#__codelineno-4-5) } [](#__codelineno-4-6) } [](#__codelineno-4-7)}` #### VS Code[¶](#vs-code "Permanent link") Create a .vscode/mcp.json file in your workspace and configure it to connect to marimo's MCP server: `[](#__codelineno-5-1){ [](#__codelineno-5-2) "servers": { [](#__codelineno-5-3) "marimo": { [](#__codelineno-5-4) "type": "http", [](#__codelineno-5-5) "url": "http://localhost:PORT/mcp/server" [](#__codelineno-5-6) } [](#__codelineno-5-7) } [](#__codelineno-5-8)}` ### DNS rebinding protection[¶](#dns-rebinding-protection "Permanent link") marimo's MCP server enables DNS rebinding protection by default, which validates the `Host` header on incoming requests. This is common when using proxies, gateways (e.g., ECS), CDNs (Cloudflare), or custom domains, where the forwarded `Host` header won't match the expected local host, causing `421 Misdirected Request` or `Invalid Host Header` errors. Pass `--mcp-allow-remote` to disable this check: `[](#__codelineno-6-1)marimo edit notebook.py --mcp --mcp-allow-remote` MCP Client[¶](#mcp-client "Permanent link") ------------------------------------------- marimo can connect to external MCP servers to add additional tools and context to the [chat panel](https://docs.marimo.io/guides/editor_features/ai_completion/#chat-panel). ### Supported servers[¶](#supported-servers "Permanent link") marimo currently supports the following MCP servers: | Server | Description | | --- | --- | | `marimo` | Provides marimo's official documentation, API reference, and code examples | | `context7` | Fetches up-to-date, version-specific documentation and code examples from official sources | ### Configuration[¶](#configuration "Permanent link") Enable MCP client servers through the marimo settings UI: Enable MCP servers in the AI settings panel. Alternatively, configure MCP servers in your marimo configuration file: marimo.toml `[](#__codelineno-7-1)[mcp] [](#__codelineno-7-2)presets = ["marimo", "context7"]` Once configured, tools from these servers will be automatically available in the [chat panel when using ask mode](https://docs.marimo.io/guides/editor_features/ai_completion/#chat-panel). Custom MCP servers Support for custom MCP server configuration is not yet available. * [AI tools](https://docs.marimo.io/guides/editor_features/tools/) - Available tools exposed by the MCP server * [AI-assisted coding](https://docs.marimo.io/guides/editor_features/ai_completion/#chat-panel) - Using the chat panel with MCP tools AI tools - marimo https://docs.marimo.io/guides/editor_features/tools/ Experimental Feature Tools are currently experimental and under active development. Tool definitions and availability may change. marimo exposes a set of tools that allow AI assistants to interact with your notebooks. These tools enable AI agents to read notebook content, inspect cell runtime data, access variables, handle errors, and more. These tools are available when using the [chat panel in ask mode](https://docs.marimo.io/guides/editor_features/ai_completion/#chat-panel). External AI applications can also access these tools through the [marimo MCP server](https://docs.marimo.io/guides/editor_features/mcp/#mcp-server). ### Inspection[¶](#inspection "Permanent link") | Tool | Description | | --- | --- | | **get\_active\_notebooks** | List all currently active marimo notebooks. Returns summary statistics and notebook details including names, paths, and session IDs. Start here to discover which notebooks are available. | | **get\_lightweight\_cell\_map** | Get an overview of notebook structure showing a preview of each cell. Takes a `session_id` and optional `preview_lines` parameter. Returns cell IDs, preview text, line counts, cell types (code, markdown, SQL), runtime state (`idle`, `running`, `queued`, etc.), and `has_output`/`has_console_output` flags. | | **get\_cell\_runtime\_data** | Get detailed runtime information for one or more cells. Takes `session_id` and `cell_ids` (list) parameters. Returns full cell code, error details, runtime metadata (execution time, runtime state), and variables defined by each cell. | | **get\_cell\_outputs** | Get execution output from one or more cells. Takes `session_id` and `cell_ids` (list) parameters. Returns visual output (HTML, charts, tables, etc.) with mimetype, stdout messages, and stderr messages for each cell. | | **get\_cell\_dependency\_graph** | Get the cell dependency graph showing variable ownership and cell relationships. Takes `session_id` and optional `cell_id` and `depth` parameters. Returns cell dependency info (defined variables with kind and runtime type, referenced variables, parent/child cells), a variable ownership map, multiply-defined variables, and cycle information. Use `cell_id` to center on a specific cell and `depth` to limit traversal hops. | ### Data[¶](#data "Permanent link") | Tool | Description | | --- | --- | | **get\_tables\_and\_variables** | Get information about variables and data tables in a session. Takes `session_id` and `variable_names` parameters (empty list returns all). Returns table metadata (columns, primary keys, indexes, row counts) and variable values with data types. | | **get\_database\_tables** | Get database schema information with optional query filtering. Takes `session_id` and optional `query` parameter (supports regex). Returns tables with connection name, database, schema, and table details. | ### Debugging[¶](#debugging "Permanent link") | Tool | Description | | --- | --- | | **get\_notebook\_errors** | Get all errors in the notebook organized by cell. Takes `session_id` parameter. Returns error summary (total errors, affected cells) and per-cell error details (type, message, traceback). | | **lint\_notebook** | Get all marimo lint errors in the notebook. Returns lint errors as defined in the [lint rules documentation](https://docs.marimo.io/guides/lint_rules/). | ### Reference[¶](#reference "Permanent link") | Tool | Description | | --- | --- | | **get\_marimo\_rules** | Get official marimo guidelines and best practices for AI assistants. Returns the content of the marimo rules file and source URL for understanding marimo-specific conventions. | ### Editing (Agent mode only)[¶](#editing-agent-mode-only "Permanent link") | Tool | Description | | --- | --- | | **edit\_notebook** | Add, remove, or update cells in the notebook. Takes cell operations and modifications as parameters. Allows the AI agent to generate diffs that modify notebook structure and content. | | **run\_stale\_cells** | Run cells that are stale (outdated due to upstream changes). Triggers execution of affected cells to update the notebook state. | * [Model Context Protocol (MCP)](https://docs.marimo.io/guides/editor_features/mcp/) - Learn how to expose tools through the marimo MCP server * [AI-assisted coding](https://docs.marimo.io/guides/editor_features/ai_completion/) - Learn about more AI coding features Agents - marimo https://docs.marimo.io/guides/editor_features/agents/ Experimental Feature Agents are currently experimental and under active development. Features and APIs may change. marimo supports external AI agents that can interact with your codebase through the [Agent Client Protocol](https://agentclientprotocol.com/) (ACP). Agents can read and write marimo notebooks, helping you with coding tasks directly from the chat panel. Supported agents[¶](#supported-agents "Permanent link") ------------------------------------------------------- marimo currently supports the following agents: ### Claude Code Agent[¶](#claude-code-agent "Permanent link") Claude Code Agent that uses your [Claude Code CLI subscription](https://docs.claude.com/en/docs/claude-code/overview) to help you with coding tasks. **Installation and login:** `[](#__codelineno-0-1)# Install [](#__codelineno-0-2)npm install -g @anthropic-ai/claude-code [](#__codelineno-0-3)# Login [](#__codelineno-0-4)claude [](#__codelineno-0-5)# Then type /login` **Connection command:** macOS/LinuxWindows `[](#__codelineno-1-1)npx stdio-to-ws "npx @zed-industries/claude-code-acp" --port 3017` `[](#__codelineno-2-1)npx stdio-to-ws "cmd /c npx @zed-industries/claude-code-acp" --port 3017` ### Gemini Agent[¶](#gemini-agent "Permanent link") Google's Gemini agent offers a limited free tier and login for more advanced features. See login and authentication instructions in the [Gemini CLI documentation](https://github.com/google-gemini/gemini-cli?tab=readme-ov-file#-authentication-options). **Connection command:** macOS/LinuxWindows `[](#__codelineno-3-1)npx stdio-to-ws "npx @google/gemini-cli --experimental-acp" --port 3019` `[](#__codelineno-4-1)npx stdio-to-ws "cmd /c npx @google/gemini-cli --experimental-acp" --port 3019` ### Codex Agent[¶](#codex-agent "Permanent link") OpenAI's Codex agent uses [Codex CLI](https://github.com/openai/codex) via the [`@zed-industries/codex-acp`](https://github.com/zed-industries/codex-acp) adapter. **Installation and login:** `[](#__codelineno-5-1)# Install Codex CLI [](#__codelineno-5-2)npm install -g @openai/codex [](#__codelineno-5-3)# or: brew install --cask codex [](#__codelineno-5-4)[](#__codelineno-5-5)# Login (or set OPENAI_API_KEY / CODEX_API_KEY) [](#__codelineno-5-6)codex` **Connection command:** macOS/LinuxWindows `[](#__codelineno-6-1)npx stdio-to-ws "npx @zed-industries/codex-acp" --port 3021` `[](#__codelineno-7-1)npx stdio-to-ws "cmd /c npx @zed-industries/codex-acp" --port 3021` ### OpenCode Agent[¶](#opencode-agent "Permanent link") [OpenCode](https://opencode.ai/) is an open source AI coding agent built for the terminal, but also supports ACP. **Installation:** `[](#__codelineno-8-1)# Install [](#__codelineno-8-2)npm install -g opencode-ai@latest [](#__codelineno-8-3)[](#__codelineno-8-4)# You can now use and configure opencode from the commandline [](#__codelineno-8-5)opencode` **Connection command:** macOS/LinuxWindows `[](#__codelineno-9-1)npx stdio-to-ws "npx opencode-ai acp" --port 3023` `[](#__codelineno-10-1)npx stdio-to-ws "cmd /c npx opencode-ai acp" --port 3023` Opencode supports many models, including local ones through Ollama, and can be configured via a [configuration file](https://opencode.ai/docs/config/). `[](#__codelineno-11-1){ [](#__codelineno-11-2) "$schema": "https://opencode.ai/config.json", [](#__codelineno-11-3) "provider": { [](#__codelineno-11-4) "ollama": { [](#__codelineno-11-5) "npm": "@ai-sdk/openai-compatible", [](#__codelineno-11-6) "options": { [](#__codelineno-11-7) "baseURL": "http://localhost:11434/v1" [](#__codelineno-11-8) }, [](#__codelineno-11-9) "models": { [](#__codelineno-11-10) "": { [](#__codelineno-11-11) "tools": true [](#__codelineno-11-12) } [](#__codelineno-11-13) } [](#__codelineno-11-14) } [](#__codelineno-11-15) } [](#__codelineno-11-16)}` If you choose to use a local model with Ollama, make sure that you set the maximum context length to be much higher than the 4K default. [This video tutorial](https://www.youtube.com/watch?v=4hUI2GF90nQ) explains how to set this up. Opencode can also be configured to use remote models like those hosted by [OpenRouter](https://openrouter.ai/) or via [the Zen service](https://opencode.ai/docs/zen/). For more information on configuring OpenCode providers, see the [provider documentation](https://opencode.ai/docs/providers). Connecting to an agent[¶](#connecting-to-an-agent "Permanent link") ------------------------------------------------------------------- 1. **Start the agent server**: Run the connection command for your chosen agent in a terminal 2. **Enable the feature flag**: Enable the feature flag under the "Lab" section in the settings menu 3. **Open the agent panel**: Click the agents icon in marimo's sidebar 4. **Select your agent**: Choose the agent from the dropdown menu 5. **Start chatting**: The agent can now read and modify your notebooks Terminal integration If you have terminal access enabled in marimo, you can run agent connection commands directly from the agent panel using the terminal button. Auto-run on agent edits By default, when an agent modifies your notebook, cells are marked as stale instead of running automatically. To have cells run automatically when the agent saves changes, add this configuration to your `pyproject.toml`: `[](#__codelineno-12-1)[tool.marimo.runtime] [](#__codelineno-12-2)watcher_on_save = "autorun"` This provides a more seamless experience when working with agents, as you'll see results immediately after the agent makes changes. Custom agents[¶](#custom-agents "Permanent link") ------------------------------------------------- Custom agents Support for custom agents is coming soon. This will allow you to connect to your own ACP-compatible agents Troubleshooting[¶](#troubleshooting "Permanent link") ----------------------------------------------------- **Connection issues**: Ensure the agent server is running on the correct port before connecting in marimo. **Permission requests**: Agents may request permission to read or write files. Review these carefully before approving. **Session limits**: Currently, only one session per agent is supported for optimal performance. Language Server - marimo https://docs.marimo.io/guides/editor_features/language_server/ Language Server Protocol (LSP)[¶](#language-server-protocol-lsp "Permanent link") --------------------------------------------------------------------------------- The marimo editor supports the Language Server Protocol (LSP) to provide enhanced code intelligence features like: * Code completion * Hover information * Go to definition * Error checking and diagnostics Multiple language servers can be run simultaneously. When enabled, their results are merged — for example, you can get completions from pylsp and diagnostics from basedpyright at the same time. Supported language servers[¶](#supported-language-servers "Permanent link") --------------------------------------------------------------------------- ### pylsp (python-lsp-server)[¶](#pylsp-python-lsp-server "Permanent link") The core Python language server providing completions, hover, go-to-definition, diagnostics, code actions, rename, and signature help. **Install:** `[](#__codelineno-0-1)pip install "marimo[lsp]" [](#__codelineno-0-2)# or [](#__codelineno-0-3)uv add "marimo[lsp]" [](#__codelineno-0-4)# or [](#__codelineno-0-5)conda install -c conda-forge python-lsp-server python-lsp-ruff` This installs: * [`python-lsp-server`](https://github.com/python-lsp/python-lsp-server): The core Python language server * [`python-lsp-ruff`](https://github.com/python-lsp/python-lsp-ruff): Ruff integration for fast linting You may optionally install other `pylsp` plugins (e.g. `pylsp-mypy`). **Configuration:** pyproject.toml `[](#__codelineno-1-1)[tool.marimo.language_servers.pylsp] [](#__codelineno-1-2)enabled = true # Enable/disable pylsp [](#__codelineno-1-3)enable_mypy = true # Type checking with mypy (enabled by default, if installed) [](#__codelineno-1-4)enable_ruff = true # Linting with ruff (enabled by default, if installed) [](#__codelineno-1-5)enable_flake8 = false # Linting with flake8 [](#__codelineno-1-6)enable_pydocstyle = false # Check docstring style [](#__codelineno-1-7)enable_pylint = false # Linting with pylint [](#__codelineno-1-8)enable_pyflakes = false # Syntax checking with pyflakes` ### basedpyright[¶](#basedpyright "Permanent link") A type checker for Python built on Pyright. In marimo, basedpyright is used for **diagnostics only** (type checking errors and warnings). **Install:** `[](#__codelineno-2-1)uv pip install basedpyright` **Configuration:** pyproject.toml `[](#__codelineno-3-1)[tool.marimo.language_servers.basedpyright] [](#__codelineno-3-2)enabled = true` See the [basedpyright docs](https://docs.basedpyright.com/) for more information. ### ty[¶](#ty "Permanent link") A type checker for Python from [Astral](https://astral.sh/) (the creators of Ruff). In marimo, ty is used for **diagnostics only**. **Install:** **Configuration:** pyproject.toml `[](#__codelineno-5-1)[tool.marimo.language_servers.ty] [](#__codelineno-5-2)enabled = true` See the [ty docs](https://docs.astral.sh/ty/features/language-server/) for more information. ### pyrefly[¶](#pyrefly "Permanent link") A type checker for Python from Meta. Pyrefly provides completions, hover, go-to-definition, and diagnostics. **Install:** **Configuration:** pyproject.toml `[](#__codelineno-7-1)[tool.marimo.language_servers.pyrefly] [](#__codelineno-7-2)enabled = true` See the [pyrefly docs](https://pyrefly.org/en/docs/IDE-features/) for more information. ### GitHub Copilot[¶](#github-copilot "Permanent link") AI-powered code completions via the GitHub Copilot language server. Copilot is configured separately from the other language servers through the completion settings. **Configuration:** pyproject.toml `[](#__codelineno-8-1)[tool.marimo.completion] [](#__codelineno-8-2)copilot = "github"` See the [AI completion guide](https://docs.marimo.io/guides/editor_features/ai_completion/#github-copilot) for more details on Copilot setup and configuration. Using multiple language servers[¶](#using-multiple-language-servers "Permanent link") ------------------------------------------------------------------------------------- You can enable multiple language servers at once. marimo uses a federated architecture that merges results from all active servers. For example, you might use pylsp for completions and code actions while relying on basedpyright or ty for stricter type-checking diagnostics. Diagnostics[¶](#diagnostics "Permanent link") --------------------------------------------- Diagnostics from all language servers can be toggled globally: pyproject.toml `[](#__codelineno-9-1)[tool.marimo.diagnostics] [](#__codelineno-9-2)enabled = true # Show diagnostics in the editor` WebAssembly[¶](#webassembly "Permanent link") --------------------------------------------- Language servers are not available when running marimo in WebAssembly. Troubleshooting[¶](#troubleshooting "Permanent link") ----------------------------------------------------- If you encounter issues with a language server: 1. Make sure you've installed the required dependencies with `uv pip install "marimo[lsp]"` 2. For basedpyright, ty, and pyrefly, ensure [Node.js](https://nodejs.org/) is installed 3. Check if the language server is enabled in your configuration 4. Try restarting the marimo server 5. Check the terminal for error messages or the log files in your marimo log directory (e.g. `~/.cache/marimo/logs/`) Package management - marimo https://docs.marimo.io/guides/editor_features/package_management/ marimo supports package management for `pip`, `uv`, `poetry`, `pixi`, and `rye`. When marimo comes across a module that is not installed, you will be prompted to install it using your preferred package manager. Once the module is installed, all cells that depend on the module will be rerun. Package Installation We use some heuristic for guessing the package name in your registry (e.g. PyPI) from the module name. It is possible that the package name is different from the module name. If you encounter an error, please file an issue or help us by adding your mapping [directly to the codebase](https://github.com/marimo-team/marimo/blob/main/marimo/_runtime/packages/module_name_to_pypi_name.py). Package reproducibility[¶](#package-reproducibility "Permanent link") --------------------------------------------------------------------- marimo is the only Python notebook that is reproducible down to the packages they use. This makes it possible to share standalone notebooks without shipping `requirements.txt` files alongside them, and guarantees your notebooks will work weeks, months, even years into the future. To learn more, see the [package reproducibility guide](https://docs.marimo.io/guides/package_management/inlining_dependencies/). Using your own editor - marimo https://docs.marimo.io/guides/editor_features/watching/ While we recommend using the [marimo editor](https://docs.marimo.io/guides/editor_features/), we understand that you may prefer to use your own. marimo provides a `--watch` flag that watches your notebook file for changes, syncing them to the marimo editor or running application. This lets you edit your notebook using an editor of your choice, like neovim, VSCode, Cursor, or PyCharm, and have the changes automatically reflected in your browser. Prefer VS Code/Cursor? Try our extension! This guide teaches you how to use marimo with arbitrary text editors. If you use VS Code or Cursor, you might prefer using [our extension](https://marketplace.visualstudio.com/items?itemName=marimo-team.vscode-marimo), which provides a first-class experience for editing and running marimo notebooks. marimo's file format[¶](#marimos-file-format "Permanent link") -------------------------------------------------------------- marimo stores notebooks as Python files. Cells are stored as functions, decorated with`@app.cell`; you can optionally give cells names in the editor UI or by editing the notebook file. `[](#__codelineno-0-1)@app.cell [](#__codelineno-0-2)def memorable_cell_name(auto, determined, references): # signature denotes cell references [](#__codelineno-0-3) computed_value = auto + determined + references [](#__codelineno-0-4) "hello!" # final statement is the visual output [](#__codelineno-0-5) return computed_value # return denotes cell definitions` Run `marimo tutorial fileformat` at the command line for a full guide. Cell signature and returns Don't worry about maintaining the signatures of cells and their return values; marimo will handle this for you. ### Exposing functions and classes top-level[¶](#exposing-functions-and-classes-top-level "Permanent link") You can expose top-level functions and classes in your notebook, so that other Python modules can import them: `[](#__codelineno-1-1)from my_notebook import my_function, MyClass` Top-level functions are added to a notebook using the `@app.function` decorator, and classes with `@app.class_definition`; these appear in your notebook as cells with just a function or class definition. These functions and classes must be pure, closing over only other pure functions and classes, or imports and constants defined in an `app.setup` `with` block. Here is a complete example that you can copy/paste and run locally: `[](#__codelineno-2-1)import marimo [](#__codelineno-2-2)[](#__codelineno-2-3)app = marimo.App() [](#__codelineno-2-4)[](#__codelineno-2-5)with app.setup: [](#__codelineno-2-6) # These symbols can be used by top-level functions and classes [](#__codelineno-2-7) # (as well as by regular cells) [](#__codelineno-2-8) import numpy as np [](#__codelineno-2-9) [](#__codelineno-2-10) CONSTANT: int = 1 [](#__codelineno-2-11)[](#__codelineno-2-12)@app.function [](#__codelineno-2-13)def my_function(x: np.ndarray): [](#__codelineno-2-14) return np.mean(x) + CONSTANT [](#__codelineno-2-15)[](#__codelineno-2-16)@app.class_definition [](#__codelineno-2-17)class MyClass: [](#__codelineno-2-18) ... [](#__codelineno-2-19)[](#__codelineno-2-20)@app.cell [](#__codelineno-2-21)def _(): [](#__codelineno-2-22) my_function(np.random.randn(2, 2)) [](#__codelineno-2-23) return [](#__codelineno-2-24)[](#__codelineno-2-25)if __name__ == "__main__": [](#__codelineno-2-26) app.run()` For more details see the [guide on reusable functions and classes](https://docs.marimo.io/guides/reusing_functions/). ### Types and autocompletion[¶](#types-and-autocompletion "Permanent link") Add type hints to your variables, and marimo will carry over these type hints to cells where these variables are used. This, combined with importing modules in the setup cell (see below for an example), makes it possible for your editor to give completions on the references of your cell. For example: `[](#__codelineno-3-1)# setup cell [](#__codelineno-3-2)import numpy as np [](#__codelineno-3-3)[](#__codelineno-3-4)# cell 1 [](#__codelineno-3-5)x: np.ndarray [](#__codelineno-3-6)[](#__codelineno-3-7)# cell 2 [](#__codelineno-3-8)np.mean(x)` will be serialized as `[](#__codelineno-4-1)import marimo [](#__codelineno-4-2)[](#__codelineno-4-3)app = marimo.App() [](#__codelineno-4-4)[](#__codelineno-4-5)with app.setup: [](#__codelineno-4-6) import numpy as np [](#__codelineno-4-7)[](#__codelineno-4-8)@app.cell [](#__codelineno-4-9)def _(): [](#__codelineno-4-10) x: np.ndarray [](#__codelineno-4-11) return x, [](#__codelineno-4-12)[](#__codelineno-4-13)@app.cell [](#__codelineno-4-14)def _(x: np.ndarray): [](#__codelineno-4-15) np.mean(x) [](#__codelineno-4-16)[](#__codelineno-4-17)if __name__ == "__main__": [](#__codelineno-4-18) app.run()` ### As markdown[¶](#as-markdown "Permanent link") Markdown File format tutorial Run `marimo tutorial markdown-format` at the command line for a full guide. marimo notebooks can also be stored as Markdown files. This is a good option for prose heavy text, and can be easy to navigate and edit in external editors. To convert a marimo notebook to markdown, use `[](#__codelineno-5-1)marimo export md notebook.py -o notebook.md` at the command-line, or rename your file to have an `.md` extension in the notebook editor. marimo conforms to standard markdown document format, and will render most places like Github. Metadata in this file format is saved in the frontmatter, which marimo may use for information like [sandboxing](https://docs.marimo.io/guides/package_management/inlining_dependencies/), and the marimo version. All other fields are kept, but ignored. For execution, marimo extracts code fences that contain `marimo` in braces. For instance `python {marimo}`, `{marimo}` or `{.marimo .python}`. The marimo editor uses `python {.marimo}` which is Pandoc compatible, and correctly processed by text highlighters. ` [](#__codelineno-6-1)--- [](#__codelineno-6-2)title: My Notebook [](#__codelineno-6-3)marimo-version: 0.0.0 [](#__codelineno-6-4)description: A notebook with a description [](#__codelineno-6-5)--- [](#__codelineno-6-6)[](#__codelineno-6-7)# Just a notebook [](#__codelineno-6-8)[](#__codelineno-6-9)```python {.marimo} [](#__codelineno-6-10)print("Hello World!") [](#__codelineno-6-11)``` ` marimo's markdown format can be used with a [`mkdocs plugin`](https://github.com/marimo-team/mkdocs-marimo) and [`Quarto`](https://github.com/marimo-team/quarto-marimo). Note that the markdown format is not as fully featured as the Python format. Reactive tests will not work, markdown notebooks cannot be imported or used as a library, and they cannot be run as scripts. Watching for changes to your notebook[¶](#watching-for-changes-to-your-notebook "Permanent link") ------------------------------------------------------------------------------------------------- Install watchdog for better file watching For better performance, install [watchdog](https://pypi.org/project/watchdog/). Without watchdog, marimo resorts to polling. Watch works best with autosave Verify your settings in `User Settings` > `Editor` > `Autosave` > `Autosave enabled` ### `marimo edit --watch`[¶](#marimo-edit-watch "Permanent link") When you run `marimo edit` with the `--watch` flag, the marimo server will open your notebook in the browser and watch the underlying notebook file for changes. When you make changes to the notebook file, they will be streamed to the marimo editor in the browser. By default, synced code will not be executed automatically, with cells marked as stale instead. Run all stale cells with the marimo editor's "Run" button, or the [`runStale` hotkey](https://docs.marimo.io/guides/editor_features/hotkeys/), to see the new outputs. If you want to run all affected cells automatically when you save, change the `runtime` config in your `pyproject.toml` file. `[](#__codelineno-7-1)[tool.marimo.runtime] [](#__codelineno-7-2)watcher_on_save = "autorun"` ### `marimo run --watch`[¶](#marimo-run-watch "Permanent link") When you run `marimo run` with the `--watch` flag, whenever the file watcher detects a change to the notebook file, the application will be refreshed. The browser will trigger a page refresh to ensure your notebook starts from a fresh state. For gallery mode (`marimo run --watch`), marimo also refreshes the folder index on each workspace request. This means added and removed notebooks appear after refreshing or revisiting the gallery page. Security note for watched folders In `marimo run --watch`, newly created notebooks in that folder can appear in the gallery and execute code when opened. Only watch trusted directories, and use authentication when exposing the server remotely. Watching for changes to other modules[¶](#watching-for-changes-to-other-modules "Permanent link") ------------------------------------------------------------------------------------------------- marimo can also watch for changes to Python modules that your notebook imports, letting you edit auxiliary Python files in your own editor as well. Learn how to enable this feature in our [Module Autoreloading Guide](https://docs.marimo.io/guides/editor_features/module_autoreloading/) Watching for data changes[¶](#watching-for-data-changes "Permanent link") ------------------------------------------------------------------------- marimo supports watching data files and automatically refreshing cells that depend on them using [`mo.watch.file`](https://docs.marimo.io/api/watch/#marimo.watch.file " marimo.watch.file") and \[mo.watch.directory\]\[`marimo.watch.directory`\]. Learn more in the [watch API documentation](https://docs.marimo.io/api/watch/). Hot-reloading WebAssembly notebooks[¶](#hot-reloading-webassembly-notebooks "Permanent link") --------------------------------------------------------------------------------------------- Follow these steps to develop a notebook using your own editor while previewing it as a [WebAssembly notebook](https://docs.marimo.io/guides/wasm/) in the browser. This lets you take advantage of local development tools while seeing the notebook as it appears when deployed as a WebAssembly notebook. `[](#__codelineno-8-1)# in one terminal, start a watched edit (or run) session [](#__codelineno-8-2)marimo edit notebook.py --watch [](#__codelineno-8-3)[](#__codelineno-8-4)# in another terminal [](#__codelineno-8-5)marimo export html-wasm notebook.py -o output_dir --watch [](#__codelineno-8-6)[](#__codelineno-8-7)# in a third terminal, serve the WASM application [](#__codelineno-8-8)cd path/to/output_dir [](#__codelineno-8-9)python -m http.server # or a server that watches for changes` Run notebooks as apps - marimo https://docs.marimo.io/guides/apps/ Run as an app[¶](#run-as-an-app "Permanent link") ------------------------------------------------- The marimo CLI lets you run any notebook as an app: `marimo run` lays out the notebook as an app and starts a web server that hosts the resulting app. By default, apps are laid out as a concatenation of their outputs, with code hidden. You can customize the layout using marimo's built-in drag-and-drop grid editor; you can also choose to include code in the app view. CLI[¶](#cli "Permanent link") ----------------------------- Run marimo notebooks as apps with View the [CLI documentation](https://docs.marimo.io/cli/#marimo-run) for more details. ### Gallery[¶](#gallery "Permanent link") You can run multiple notebooks (or a directory of notebooks) as a gallery: `[](#__codelineno-1-1)marimo run folder/ [](#__codelineno-1-2)marimo run notebook_a.py notebook_b.py folder/` This shows a page with one card per notebook. Cards can use notebook OpenGraph metadata for the title, description, and thumbnail image. Configure [OpenGraph previews](https://docs.marimo.io/guides/publishing/opengraph/) and optionally generate images with [Thumbnails](https://docs.marimo.io/guides/publishing/thumbnails/). If you run a single folder with watch mode (`marimo run folder/ --watch`), the gallery index is refreshed on subsequent workspace requests so file additions and deletions show up after refreshing the gallery page. See [Using your own editor](https://docs.marimo.io/guides/editor_features/watching/) for watch behavior and security considerations. Layout[¶](#layout "Permanent link") ----------------------------------- While editing a notebook with `marimo edit`, you can preview the notebook as an app by clicking the preview button in the bottom-right of the editor. (You can also use the command palette.) `layouts` folder marimo saves metadata about your constructed layout in a `layouts` folder; make sure to include this folder when sharing or deploying your notebook so that others can reconstruct your layout. Include this folder in version control. ### Vertical layout[¶](#vertical-layout "Permanent link") The default layout is the vertical layout: cell outputs are concatenated vertically and code is hidden. When combined with marimo's [built-in functions for laying out outputs](https://docs.marimo.io/api/layouts/), as well as its configurable app widths (configure via the notebook settings menu), the vertical layout can successfully support a wide breadth of application user interfaces. ### Grid layout[¶](#grid-layout "Permanent link") If you prefer a drag-and-drop experience over [programmatic layout](https://docs.marimo.io/api/layouts/), consider using marimo's grid editor for making your apps: with this editor, you simply drag outputs onto a grid to arrange them on the page. Enable the grid editor in the app preview, via a dropdown: ### Slides layout[¶](#slides-layout "Permanent link") If you prefer a slideshow-like experience, you can use the slides layout. Enable the slides layout in the app preview, via the same dropdown as above. Unlike the grid layout, the slides are much less customizable: * The order of the slides is determined by the order of the cells in the notebook. * The slides do not support drag-and-drop rearrangement or resizing. * All outputs are shown and all code is hidden. * For PDF export, use `marimo export pdf notebook.py --as=slides --raster-server=live` for slide-style output with better capture compatibility. If you need more control over the layout, please file an issue on [GitHub](https://github.com/marimo-team/marimo/issues), so we can properly prioritize this feature. Run notebooks as scripts - marimo https://docs.marimo.io/guides/scripts/ Run as a script[¶](#run-as-a-script "Permanent link") ----------------------------------------------------- You can run marimo notebooks as scripts at the command line, just like any other Python script. For example, `[](#__codelineno-0-1)python my_marimo_notebook.py` Running a notebook as a script is useful when your notebook has side-effects, like writing to disk. Print statements and other console outputs will show up in your terminal. marimo ntoebooks can also \[double as importable modules, providing libraries of functions and classes that you can reuse in other programs: `[](#__codelineno-1-1)from my_notebook import my_function` Read our guide on [reusable functions](https://docs.marimo.io/guides/reusing_functions/) for details. Check before running Before running a notebook as a script, you can use marimo's linter to check for issues that might prevent execution: `[](#__codelineno-2-1)marimo check my_marimo_notebook.py` See the [Lint Rules](https://docs.marimo.io/guides/lint_rules/) guide for more information about marimo's linting system. Saving notebook outputs To run as a script while also saving HTML of the notebook outputs, use `[](#__codelineno-3-1)marimo export html notebook.py -o notebook.html` You can also pass command-line arguments to your notebook during export. Separate these args from the command with two dashes: `[](#__codelineno-4-1)marimo export html notebook.py -o notebook.html -- -arg value` Exporting to other formats, such as ipynb, is also possible: `[](#__codelineno-5-1)marimo export ipynb notebook.py -o notebook.ipynb -- -arg value` Command-line arguments[¶](#command-line-arguments "Permanent link") ------------------------------------------------------------------- When run as a script, you can access your notebook's command-line arguments through `sys.argv`, just like any other Python program. This also means you can declare your notebook's command-line arguments using Python libraries like [`argparse`](https://docs.python.org/3/library/argparse.html) and [`simple-parsing`](https://github.com/lebrice/SimpleParsing). These examples shows how to conditionally assign values to variables based on command-line arguments when running as a script, and use default values when running as a notebook. ### argparse[¶](#argparse "Permanent link") Source code for `examples/running_as_a_script/sharing_arguments.py` Tip: paste this code into an empty cell, and the marimo editor will create cells for you ``import marimo __generated_with = "0.19.7" app = marimo.App(width="medium") @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(): import argparse return (argparse,) @app.cell(hide_code=True) def _(mo): mo.md(""" This notebook shows how to parametrize a notebook with optional command-line arguments. Run the notebook with ```bash marimo edit sharing_arguments.py ``` or ```bash marimo edit sharing_arguments.py -- -learning_rate=1e-3 ``` (Note the `--` separating the filename from the arguments.) or ```bash python sharing_arguments.py -learning_rate=1e-3 ``` See help for the notebook's arguments with ```python python sharing_arguments.py --help ``` """) return @app.cell def _(mo): default = mo.ui.number(1000, step=100) default return (default,) @app.cell def _(argparse, default): parser = argparse.ArgumentParser() parser.add_argument("-iterations", default=default.value) args = parser.parse_args() print(args.iterations) return if __name__ == "__main__": app.run()`` ### simple-parsing[¶](#simple-parsing "Permanent link") Source code for `examples/running_as_a_script/with_simple_parsing.py` Tip: paste this code into an empty cell, and the marimo editor will create cells for you `# /// script # requires-python = ">=3.12" # dependencies = [ # "marimo", # "simple-parsing==0.1.7", # ] # /// import marimo __generated_with = "0.19.7" app = marimo.App(width="medium") @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(): import simple_parsing return @app.cell def _(): from dataclasses import dataclass from simple_parsing import ArgumentParser parser = ArgumentParser() parser.add_argument("--foo", type=int, default=123, help="foo help") @dataclass class Options: """Help string for this group of command-line arguments.""" log_dir: str # Help string for a required str argument learning_rate: float = 1e-4 # Help string for a float argument parser.add_arguments(Options, dest="options") return Options, parser @app.cell def _(Options, mo, parser): from dataclasses import fields def parse_args(): if mo.running_in_notebook(): # set default values for the command-line arguments when running as a notebook return "foo default", Options("logs/", 1e-4) else: args = parser.parse_args() return args.foo, args.options return (parse_args,) @app.cell def _(parse_args): foo, options = parse_args() print(foo, options) return if __name__ == "__main__": app.run()` Example: scheduled execution[¶](#example-scheduled-execution "Permanent link") ------------------------------------------------------------------------------ marimo notebooks are Python files, so any scheduler that runs Python scripts can run marimo notebooks. This includes [cron](https://en.wikipedia.org/wiki/Cron), [Airflow](https://airflow.apache.org/), [Prefect](https://www.prefect.io/), and other tools. You can pass variables from the command line and [reuse functions](https://docs.marimo.io/guides/reusing_functions/) from notebooks in other jobs as well. ### GitHub Action[¶](#github-action "Permanent link") Run notebooks on a schedule with [GitHub Actions](https://docs.github.com/en/actions/reference/events-that-trigger-workflows#schedule). This example assumes [inline dependencies](https://docs.marimo.io/guides/package_management/inlining_dependencies/): `[](#__codelineno-6-1)name: Run marimo notebook daily [](#__codelineno-6-2)[](#__codelineno-6-3)on: [](#__codelineno-6-4) schedule: [](#__codelineno-6-5) - cron: '0 9 * * *' [](#__codelineno-6-6)[](#__codelineno-6-7)jobs: [](#__codelineno-6-8) run-marimo: [](#__codelineno-6-9) runs-on: ubuntu-latest [](#__codelineno-6-10) steps: [](#__codelineno-6-11) - uses: actions/checkout@v4 [](#__codelineno-6-12) - uses: actions/setup-python@v5 [](#__codelineno-6-13) with: [](#__codelineno-6-14) python-version: '3.12' [](#__codelineno-6-15) - uses: astral-sh/setup-uv@v7 [](#__codelineno-6-16) - run: uv run path/to/notebook.py` Reuse functions and classes - marimo https://docs.marimo.io/guides/reusing_functions/ Importing functions and classes defined in notebooks[¶](#importing-functions-and-classes-defined-in-notebooks "Permanent link") ------------------------------------------------------------------------------------------------------------------------------- You can import top-level functions and classes defined in a marimo notebook into other Python scripts or notebooks using normal Python syntax, as long as your definitions satisfy the simple criteria described on this page. This makes your notebook code reusable, testable, and easier to edit in text editors of your choice. > Prefer learning by video? Watch our [tutorial on YouTube](https://youtu.be/4AFcgd-s3Fg). Overview[¶](#overview "Permanent link") --------------------------------------- For a function or class to be saved at the top level of the notebook file, it must meet the following **criteria**: 1. The cell must define just a single function or class. 2. The defined function or class can only refer to symbols defined in the [setup cell](#1-create-a-setup-cell), or to other top-level symbols. ### Example[¶](#example "Permanent link") In another script or notebook `[](#__codelineno-1-1)from my_notebook import my_utility_function, DataProcessor` Creating a top-level function or class[¶](#creating-a-top-level-function-or-class "Permanent link") --------------------------------------------------------------------------------------------------- ### 1\. Create a setup cell[¶](#1-create-a-setup-cell "Permanent link") First, add a **setup cell** to your notebook for imports that your functions or classes will need: To add a setup cell in the editor, open the notebook menu and select "Add setup cell". (The setup cell is guaranteed to run before other cells.) ### 2\. Define your function[¶](#2-define-your-function "Permanent link") Define a single function in a cell. If the [criteria](#overview) for top-level functions are met, a marker in the bottom right will indicate that it is a reusable function. Note Functions can only reference symbols defined in the setup cell. If a function cannot be serialized top-level, the marker in the bottom right will provide a description why. Under the hood, marimo decorates top-level functions with `@app.function`, which you can use to define your own top-level functions if you are editing a notebook file directly. Top-level classes are decorated with `@app.class_definition`. ### 3\. Import into other Python files[¶](#3-import-into-other-python-files "Permanent link") Now you can import your function in other notebooks or Python scripts: `[](#__codelineno-4-1)# In another_script.py [](#__codelineno-4-2)from my_notebook import calculate_statistics [](#__codelineno-4-3)[](#__codelineno-4-4)data = [1, 2, 3, 4, 5] [](#__codelineno-4-5)stats = calculate_statistics(data) [](#__codelineno-4-6)print(stats)` Best practices[¶](#best-practices "Permanent link") --------------------------------------------------- * Use setup cells for widely used imports * Keep function dependencies limited to setup-cell references, or other top-level declarations * Use descriptive names for your functions * Add docstrings to document your functions' behavior Tip Top-level symbols can reference other top-level symbols. Limitations[¶](#limitations "Permanent link") --------------------------------------------- * Functions cannot depend on variables defined in regular cells * Like other cells, cyclic dependencies between functions are not allowed * Local variables (variables starting with `_`) cannot be made reusable * Functions cannot be exported from notebooks in [marimo's markdown format](https://docs.marimo.io/guides/editor_features/watching/#as-markdown). Learn more[¶](#learn-more "Permanent link") ------------------------------------------- For more on marimo's file format, check out our [documentation on using your own editor](https://docs.marimo.io/guides/editor_features/watching/) or view our [file format tutorial](https://links.marimo.app/tutorial-fileformat). Export to other formats - marimo https://docs.marimo.io/guides/exporting/ Export marimo notebooks to other file formats from the browser editor. Notebooks can also be exported to other formats at the command-line with: Looking to share notebooks online? For sharing interactive notebooks on the public web, consider using [molab](https://docs.marimo.io/guides/molab/), our free cloud-hosted notebook platform. Available formats[¶](#available-formats "Permanent link") --------------------------------------------------------- | Format | Command | Description | | --- | --- | --- | | [Static HTML](https://docs.marimo.io/guides/exporting/static_html/) | `marimo export html` | Non-interactive HTML snapshot | | [PDF](https://docs.marimo.io/guides/exporting/pdf/) | `marimo export pdf` | PDF document or slide deck | | [Jupyter notebook](https://docs.marimo.io/guides/exporting/jupyter_notebook/) | `marimo export ipynb` | Jupyter `.ipynb` file | | [Python script](https://docs.marimo.io/guides/exporting/python_script/) | `marimo export script` | Flat `.py` script in topological order | | [Markdown](https://docs.marimo.io/guides/exporting/markdown/) | `marimo export md` | Markdown with code blocks | | [WebAssembly HTML](https://docs.marimo.io/guides/exporting/webassembly_html/) | `marimo export html-wasm` | Self-contained, interactive HTML powered by WebAssembly | | [Session snapshot](https://docs.marimo.io/guides/exporting/sessions/) | `marimo export session` | Serialized session snapshot (JSON) | Static HTML - marimo https://docs.marimo.io/guides/exporting/static_html/ Export your notebook to a static, non-interactive HTML file. Export from the marimo editor[¶](#export-from-the-marimo-editor "Permanent link") --------------------------------------------------------------------------------- Export the current view of your notebook to static HTML via the notebook menu: Download as static HTML. Additionally, you can configure individual notebooks to automatically save as HTML through the notebook menu. These automatic snapshots are saved to a folder called `__marimo__` in the notebook directory. Download as static HTML. Export from the command line[¶](#export-from-the-command-line "Permanent link") ------------------------------------------------------------------------------- Export to HTML at the command line: `[](#__codelineno-0-1)marimo export html notebook.py -o notebook.html` Exclude code from the export: `[](#__codelineno-1-1)marimo export html --no-include-code notebook.py -o notebook.html --watch` Export the notebook whenever it changes on disk: `[](#__codelineno-2-1)marimo export html notebook.py -o notebook.html --watch` **Exporting runs your notebook.** When you export from the command line, marimo runs your notebook to produce its visual outputs before saving as HTML. **Errors.** If any cells error during the export process, the status code will be non-zero. However, the export result may still be generated, with the error included in the output. Errors can be ignored by appending `|| true` to the command, e.g. `marimo export html notebook.py || true`. Pre-render HTML exports[¶](#pre-render-html-exports "Permanent link") --------------------------------------------------------------------- Static marimo exports execute Javascript to render the notebook source code as HTML at browser runtime. If you would like to directly serve the HTML representation of your notebook, you can run the following post-processing script and serve the resulting file instead. `[](#__codelineno-3-1)# /// script [](#__codelineno-3-2)# requires-python = ">=3.9" [](#__codelineno-3-3)# dependencies = [ [](#__codelineno-3-4)# "playwright", [](#__codelineno-3-5)# ] [](#__codelineno-3-6)# /// [](#__codelineno-3-7)[](#__codelineno-3-8)import os [](#__codelineno-3-9)import subprocess [](#__codelineno-3-10)from playwright.sync_api import sync_playwright [](#__codelineno-3-11)[](#__codelineno-3-12)input_file = "input.html" [](#__codelineno-3-13)output_file = "output.html" [](#__codelineno-3-14)[](#__codelineno-3-15)subprocess.run(["playwright", "install", "chromium-headless-shell"], check=True) [](#__codelineno-3-16)[](#__codelineno-3-17)with sync_playwright() as p: [](#__codelineno-3-18) with p.chromium.launch(headless=True) as browser: [](#__codelineno-3-19) page = browser.new_page() [](#__codelineno-3-20) page.goto( [](#__codelineno-3-21) f"file:///{os.path.abspath(input_file)}", [](#__codelineno-3-22) wait_until="networkidle", [](#__codelineno-3-23) ) [](#__codelineno-3-24) with open(output_file, "w", encoding="utf-8") as f: [](#__codelineno-3-25) f.write(page.content())` Run in the cloud with molab - marimo https://docs.marimo.io/guides/molab/ Contribute to our community gallery! We welcome submissions to our curated [community gallery](https://marimo.io/gallery?tag=community). To propose an example, share your notebook on socials and [tag us](https://docs.marimo.io/guides/publishing/public_gallery/). [molab](https://molab.marimo.io/notebooks) is a free cloud-hosted marimo notebook environment. molab is designed for sharing, and is integrated with GitHub; notebooks are public but undiscoverable by default. **Highlights**. * ☁️ Use any Python package * 🤖 Generate code with AI * 📦 Install packages with a built-in package manager * 🛢️ Use a limited amount of persistent storage per notebook * 🔗 Share links and [open-in-molab badges](#share-open-in-molab-badges) * 👀 [Preview notebooks hosted on GitHub](#preview-notebooks-from-github), with interactivity * 🌐 [Embed interactive notebooks](#embed-in-other-webpages) in your own webpages * 📄 Export to PDF * 📥 Download notebooks to your machine, reuse them as Python scripts or apps * 📤 Upload local notebooks to the cloud from our CLI (coming soon) * 🕹️ Real-time collaboration (coming soon) * 🧩 Configure computational resources to obtain more CPU or GPU (coming soon) Sharing[¶](#sharing "Permanent link") ------------------------------------- To share notebooks created in molab, just share the notebook's URL. Viewers will see a static preview of your notebook and the option to fork it into their own workspace. ### Preview notebooks from GitHub[¶](#preview-notebooks-from-github "Permanent link") > See our [gallery examples](https://github.com/marimo-team/gallery-examples) repository for best practices on previewing notebooks from GitHub. In addition to sharing notebooks created in your workspace, you can also preview notebooks hosted on GitHub. In some cases, these previews can be interactive, but they are static by default. #### Static previews[¶](#static-previews "Permanent link") To construct a static (read-only, not interactive) preview, replace `github.com` in your notebook's GitHub URL with `molab.marimo.io/github`. For example, a notebook at `[](#__codelineno-0-1)https://github.com/marimo-team/gallery-examples/blob/main/notebooks/math/cellular-automaton-art.py` becomes `[](#__codelineno-1-1)https://molab.marimo.io/github/marimo-team/gallery-examples/blob/main/notebooks/math/cellular-automaton-art.py` (Visit [molab.marimo.io/github](https://molab.marimo.io/github) to automatically generate preview URLs from GitHub links.) **Rendering outputs.** In order for your static preview to include outputs, you must commit the notebook's corresponding session JSON file, in the `__marimo__/session/` directory that exists alongside the notebook. The session is automatically generated when you run the notebook from the marimo editor; you can also generate the session from the command-line with `marimo export session notebook.py` #### Interactive previews[¶](#interactive-previews "Permanent link") Interactive previews let viewers run and interact with your notebook before forking it. Append `/wasm` to the static preview URL to construct an interactive preview. For example: `[](#__codelineno-2-1)https://molab.marimo.io/github/marimo-team/gallery-examples/blob/main/notebooks/math/cellular-automaton-art.py/wasm` Your notebook must be [WebAssembly-compatible](https://docs.marimo.io/guides/wasm/) for interactive previews to work. We also recommend creating these notebooks [with `--sandbox`](https://docs.marimo.io/guides/package_management/inlining_dependencies/) to make sure their dependencies get installed. If you use coding agents like Claude Code, use our [official skills](https://docs.marimo.io/guides/generate_with_ai/skills/) to automatically check for WebAssembly compatibility. Share links to molab notebooks using our open in molab badge: Use the following markdown snippet (replace the notebook URL with a link to your own notebook): `[](#__codelineno-3-1)[![Open in molab](https://marimo.io/molab-shield.svg)](https://molab.marimo.io/github/marimo-team/gallery-examples/blob/main/notebooks/math/cellular-automaton-art.py)` For notebooks hosted on GitHub, use our [badge generator](https://molab.marimo.io/github) to automatically generate embeddable links. If you want the preview to be interactive (and if your notebook is [WebAssembly-compatible](https://docs.marimo.io/guides/wasm/)), append `/wasm` to the URL. Embed in other webpages[¶](#embed-in-other-webpages "Permanent link") --------------------------------------------------------------------- You can embed interactive molab notebooks in your own webpages using iframes. Obtain iframe snippets by clicking the share button on interactive [molab previews of GitHub notebooks](#preview-notebooks-from-github), or construct embeddable URLs yourself using the recipes below. > Embedded notebooks run in the browser via WebAssembly, so your notebook must be [WebAssembly-compatible](https://docs.marimo.io/guides/wasm/). We also recommend creating these notebooks [with `--sandbox`](https://docs.marimo.io/guides/package_management/inlining_dependencies/) to make sure their dependencies get installed. ### Embed notebooks from GitHub[¶](#embed-notebooks-from-github "Permanent link") Add `?embed=true` to an [interactive preview URL](#interactive-previews) to get an embeddable notebook: CodeLive Example `[](#__codelineno-4-1)` ### Embed from source code[¶](#embed-from-source-code "Permanent link") You can embed a notebook directly from its source code, without hosting it on GitHub. Compress your notebook code using lz-string and pass it as a URL hash: `[](#__codelineno-5-1)https://molab.marimo.io/new/wasm/?embed=true#code/{compressed}` JavaScriptPython ``[](#__codelineno-6-1)import { compressToEncodedURIComponent } from "lz-string"; [](#__codelineno-6-2)[](#__codelineno-6-3)const url = `https://molab.marimo.io/new/wasm/?embed=true#code/${compressToEncodedURIComponent(code)}`;`` `[](#__codelineno-7-1)import lzstring [](#__codelineno-7-2)[](#__codelineno-7-3)lz = lzstring.LZString() [](#__codelineno-7-4)compressed = lz.compressToEncodedURIComponent(code) [](#__codelineno-7-5)url = f"https://molab.marimo.io/new/wasm/?embed=true#code/{compressed}"` For example: CodeLive Example `[](#__codelineno-8-1)` Query parameters go before the hash: `[](#__codelineno-9-1)https://marimo.app/?embed=true#code/{compressed}` For small notebooks (under 14 KB), you can also use the `code` query parameter with URI encoding instead of lz-compression: `[](#__codelineno-10-1)https://marimo.app/new/wasm/?embed=true&code={encodedURIComponent}` ### Embed an empty editable notebook[¶](#embed-an-empty-editable-notebook "Permanent link") Use this recipe to embed an empty editable notebook: CodeLive Example `[](#__codelineno-11-1)` ### Query parameters[¶](#query-parameters "Permanent link") | Parameter | Default | Description | | --- | --- | --- | | `embed=true` | `false` | Hides the molab header for a cleaner embed | | `mode=edit` | `read` | Allows viewers to edit code cells | | `include-code=false` | `true` | Excludes code entirely (only works with `mode=read`) | | `show-code=false` | `true` | Hides code by default, but viewers can still reveal it | Features[¶](#features "Permanent link") --------------------------------------- ### Package management[¶](#package-management "Permanent link") Each notebook runs in an environment with several popular packages pre-installed, including torch, numpy, polars, and more. marimo’s built-in package manager will install additional packages as you import them (use the package manager panel to install specific package versions). ### Storage[¶](#storage "Permanent link") Notebooks get a limited amount of persistent storage; view the file tree by clicking the file icon in the sidebar. From here you can upload additional data files. ### Run notebooks locally[¶](#run-notebooks-locally "Permanent link") You can download the notebook directory by clicking the download button, also on the top-right. You can also just pass the notebook URL to marimo edit. For example: `[](#__codelineno-12-1)marimo edit https://molab.marimo.io/notebooks/nb_TWVGCgZZK4L8zj5ziUBNVL` Currently, this brings just the notebook file down, and does not include your attached storage. FAQ[¶](#faq "Permanent link") ----------------------------- **What’s the difference between molab and Google Colab?** Google Colab is a hosted Jupyter notebook service provider. molab is a hosted [marimo notebook](https://github.com/marimo-team/marimo) service with similar compute and sharing capabilities, but powered by marimo notebooks instead of Jupyter. Unlike Colab, molab also supports embedding interactive notebooks in your own webpages, no login required. **Is molab free?** Yes. **How do I get more RAM, CPU or GPUs?** [Reach out to us](https://marimo.io/discord) and we’ll see what we can do. **How does molab relate to marimo’s open source notebook?** molab is a hosted offering of marimo’s open source notebook with cloud-based compute and sharing capabilities. You can use marimo open source on your own machine or on your own remote servers. **I’m a compute provider. How do I get plugged into molab as an offered backend?** [Get in touch](mailto:contact@marimo.io). **How does molab relate to marimo’s WebAssembly playground?** The [WebAssembly playground](https://marimo.app/) runs notebooks entirely in the browser through [Pyodide](https://pyodide.org/en/stable/). This makes for a snappy user experience, at the cost of limited compute and limited support for Python packages. The playground is well-suited for lightweight notebooks and embedding interactive notebooks in documentation, but it is not well-suited for modern ML or AI workflows. molab bridges the gap: develop notebooks with the full power of Python running on a traditional server, and (when compatible) share interactive previews using WebAssembly, which others can fork and develop further using a server-backed notebook. **Why are you making molab?** See our [announcement blog post](https://marimo.io/blog/announcing-molab). Jupyter notebook - marimo https://docs.marimo.io/guides/exporting/jupyter_notebook/ Export marimo notebooks to Jupyter `.ipynb` format. This lets you go from marimo into the vast Jupyter export ecosystem, including tools like `nbconvert`, Quarto, JupyterBook, and more. Export from the marimo editor[¶](#export-from-the-marimo-editor "Permanent link") --------------------------------------------------------------------------------- You can configure individual notebooks to automatically save as ipynb through the notebook menu. These automatic snapshots are saved to a folder called `__marimo__` in the notebook directory. Download as static HTML. Export from the command line[¶](#export-from-the-command-line "Permanent link") ------------------------------------------------------------------------------- Export to Jupyter notebook in topological order, so the notebook can be run from top to bottom: `[](#__codelineno-0-1)marimo export ipynb notebook.py -o notebook.ipynb` Export with cells in the same order as the marimo notebook: `[](#__codelineno-1-1)marimo export ipynb notebook.py -o notebook.ipynb --sort=top-down` See all options: `[](#__codelineno-2-1)marimo export ipynb notebook.py -o notebook.ipynb --sort=top-down` Convert back to a marimo notebook[¶](#convert-back-to-a-marimo-notebook "Permanent link") ----------------------------------------------------------------------------------------- You can also convert a Jupyter notebook back to a marimo notebook: `[](#__codelineno-3-1)marimo convert notebook.ipynb -o notebook.py` PDF - marimo https://docs.marimo.io/guides/exporting/pdf/ Export marimo notebooks to PDF documents or slide decks. > PDF export works out-of-the-box on on [molab](https://molab.marimo.io/notebooks). Export to PDF from the marimo editor[¶](#export-to-pdf-from-the-marimo-editor "Permanent link") ----------------------------------------------------------------------------------------------- Export to PDF from the notebooks action menu. This requires a few dependencies, which you will be prompted to install. It also requires LaTeX to install. Download as PDF. You can also export to PDF from the command palette (Ctrl/Cmd+K). Export to PDF from the command line[¶](#export-to-pdf-from-the-command-line "Permanent link") --------------------------------------------------------------------------------------------- You can export directly with marimo: `[](#__codelineno-0-1)marimo export pdf notebook.py -o notebook.pdf` To exclude code cells: `[](#__codelineno-1-1)marimo export pdf --no-include-inputs notebook.py -o notebook.pdf` To see all options, use ### Rasterized output capture[¶](#rasterized-output-capture "Permanent link") Rasterized PNG fallback capture for marimo widget HTML (including anywidgets) and Vega outputs is enabled by default. Use `--no-rasterize-outputs` to disable it. Use `--raster-scale` (range `1.0` to `4.0`, default `4.0`) to trade export speed/file size for sharper captured output. Use `--raster-server=static` (default) for a static capture page, or `--raster-server=live` to capture through a live notebook server. Choose the raster server mode carefully marimo gives you control over how output is captured. Use `--raster-server=live` when a widget needs Python to finish rendering. Otherwise, prefer the default `--raster-server=static`. The notebook below is a concrete case where `--raster-server=live` helps. Source code for `examples/outputs/live_raster.py` Tip: paste this code into an empty cell, and the marimo editor will create cells for you ``# /// script # requires-python = ">=3.13" # dependencies = [ # "anywidget==0.9.21", # "marimo>=0.20.2", # "traitlets==5.14.3", # ] # /// import marimo __generated_with = "unknown" app = marimo.App(width="medium") @app.cell(hide_code=True) def _(CounterWidget): CounterWidget(count=42) return @app.cell def _(anywidget, os, traitlets): class CounterWidget(anywidget.AnyWidget): _esm = """ export default async () => { let hostName = null; return { initialize({ model }) { // This message gets handled by _handle_custom_msg on the Python side model.send({ event: "requestHostName" }); }, render({ model, el }) { let count = () => model.get("count"); let btn = document.createElement("button"); btn.classList.add("counter-button"); btn.innerHTML = `Initializing...`; // Set proper HTML content once message arrives from Python connection model.on("msg:custom", (msg, buffers) => { hostName = msg.response; btn.innerHTML = `count is ${count()} from ${hostName} host`; }); btn.addEventListener("click", () => { model.set("count", count() + 1); model.save_changes(); }); model.on("change:count", () => { btn.innerHTML = hostName ? `count is ${count()} from ${hostName} host` : `Initializing...`; }); el.appendChild(btn); }, }; }; """ _css = """ .counter-button { background: #387262; border: 0; border-radius: 10px; padding: 10px 50px; color: white; } """ count = traitlets.Int(0).tag(sync=True) def __init__(self, **kwargs): super().__init__(**kwargs) self.on_msg(self._handle_custom_msg) def _handle_custom_msg(self, *args, **kwargs): self.send({"response": os.name}) return (CounterWidget,) @app.cell(hide_code=True) def _(): import marimo as mo import anywidget import traitlets import os return anywidget, os, traitlets if __name__ == "__main__": app.run()`` This widget starts at `Initializing...` and then updates to `count is ... from ... host` after it receives data from Python. Static capture can freeze the initial placeholder; live capture gets the updated output. `[](#__codelineno-3-1)# Static mode captures only the initial "Initializing..." placeholder [](#__codelineno-3-2)marimo export pdf examples/outputs/live_raster.py \ [](#__codelineno-3-3) -o live-raster-static.pdf --raster-server=static --no-sandbox --no-include-inputs [](#__codelineno-3-4)[](#__codelineno-3-5)# Live mode captures the updated widget output [](#__codelineno-3-6)marimo export pdf examples/outputs/live_raster.py \ [](#__codelineno-3-7) -o live-raster-live.pdf --raster-server=live --no-sandbox --no-include-inputs` Rasterization dependencies Rasterized output capture requires Playwright and Chromium: `[](#__codelineno-4-1)uv pip install playwright [](#__codelineno-4-2)playwright install chromium` ### Slides[¶](#slides "Permanent link") To export as a slides PDF, use the slides preset: `[](#__codelineno-5-1)marimo export pdf notebook.py -o notebook.pdf --as=slides --raster-server=live` `--raster-server=live` is recommended for slide exports because it better preserves slide aspect ratio and captures widget-heavy outputs more reliably. Available presets: * `--as=document`: Standard document PDF (default) * `--as=slides`: Slide-style PDF using reveal.js print layout Export to PDF using Quarto[¶](#export-to-pdf-using-quarto "Permanent link") --------------------------------------------------------------------------- The marimo [Quarto](https://www.github.com/marimo-team/quarto-marimo) plugin enables exporting to PDF and other formats with Pandoc. See [Publishing with Quarto](https://docs.marimo.io/guides/exporting/quarto/) for more details. ### Export via Jupyter notebook[¶](#export-via-jupyter-notebook "Permanent link") If you export to a Jupyter notebook, you can leverage various Jupyter ecosystem tools. For PDFs, you will need to have [Pandoc](https://nbconvert.readthedocs.io/en/latest/install.html#installing-pandoc) and [TeX](https://nbconvert.readthedocs.io/en/latest/install.html#installing-tex) installed. The examples below use `uvx`, which you can obtain by [installing `uv`](https://docs.astral.sh/uv/getting-started/installation/). `[](#__codelineno-6-1)NOTEBOOK=notebook.ipynb [](#__codelineno-6-2)[](#__codelineno-6-3)# Convert to PDF using nbconvert [](#__codelineno-6-4)uvx --with nbconvert --from jupyter-core jupyter nbconvert --to pdf $NOTEBOOK [](#__codelineno-6-5)[](#__codelineno-6-6)# Convert to web PDF [](#__codelineno-6-7)uvx --with "nbconvert[webpdf]" --from jupyter-core jupyter nbconvert --to webpdf $NOTEBOOK --allow-chromium-download [](#__codelineno-6-8)[](#__codelineno-6-9)# Convert to slides [](#__codelineno-6-10)uvx --with nbconvert --from jupyter-core jupyter nbconvert --to slides $NOTEBOOK [](#__codelineno-6-11)[](#__codelineno-6-12)# Convert to rst with nbconvert [](#__codelineno-6-13)uvx --with nbconvert --from jupyter-core jupyter nbconvert --to rst $NOTEBOOK [](#__codelineno-6-14)[](#__codelineno-6-15)# Generate PNG/PDF of specific cells using nbconvert [](#__codelineno-6-16)uvx --with nbconvert --with jupyter --from jupyter-core jupyter nbconvert --to pdf --execute --stdout $NOTEBOOK \ [](#__codelineno-6-17) --TemplateExporter.exclude_input=True [](#__codelineno-6-18)[](#__codelineno-6-19)# Use nbconvert programmatically for more control [](#__codelineno-6-20)uv run --with nbconvert python -c " [](#__codelineno-6-21)from nbconvert import PDFExporter [](#__codelineno-6-22)import nbformat [](#__codelineno-6-23)nb = nbformat.read('$NOTEBOOK', as_version=4) [](#__codelineno-6-24)pdf_exporter = PDFExporter() [](#__codelineno-6-25)pdf_data, resources = pdf_exporter.from_notebook_node(nb) [](#__codelineno-6-26)with open('notebook.pdf', 'wb') as f: [](#__codelineno-6-27) f.write(pdf_data) [](#__codelineno-6-28)"` You can also use other tools that work with Jupyter notebooks: * [Quarto](https://quarto.org/) - Create beautiful documents, websites, presentations * [nbgrader](https://nbgrader.readthedocs.io/) - Grade notebook assignments Quarto - marimo https://docs.marimo.io/guides/exporting/quarto/ Publishing with Quarto[¶](#publishing-with-quarto "Permanent link") ------------------------------------------------------------------- [Quarto](https://quarto.org/) is a commonly used open-source scientific and technical publishing system that can be used to create documents, presentations, websites, and more. Quarto supports a variety of output formats, including HTML, PDF, and Word. marimo's [Quarto extension](https://github.com/marimo-team/quarto-marimo) allows you to utilize Quarto on marimo's markdown format to produce interactive, reactive, webpages. Try the markdown file format tutorial Learn more with `marimo tutorial markdown-format` at the command line. To encourage quarto support, `.qmd` and `.md` files are interchangeable to marimo as an editor. Python script - marimo https://docs.marimo.io/guides/exporting/python_script/ Export marimo notebooks to flat Python scripts. Export from the marimo editor[¶](#export-from-the-marimo-editor "Permanent link") --------------------------------------------------------------------------------- You can download your notebook as a Python script from the notebook menu in the editor (Download > Python). Export from the command line[¶](#export-from-the-command-line "Permanent link") ------------------------------------------------------------------------------- Export to a flat Python script in topological order. `[](#__codelineno-0-1)marimo export script notebook.py -o notebook.script.py` Top-level await not supported Exporting to a flat Python script does not support top-level await. If you have top-level await in your notebook, you can still execute the notebook as a script with `python notebook.py`. You can then reuse the notebook as a [script](https://docs.marimo.io/guides/scripts/) or a [module](https://docs.marimo.io/guides/reusing_functions/). Markdown - marimo https://docs.marimo.io/guides/exporting/markdown/ Export marimo notebooks to markdown. Outputs are not included Markdown export only includes the notebook source code (code and markdown cells). Cell outputs are not saved in the exported markdown. To include outputs, export to [static HTML](https://docs.marimo.io/guides/exporting/static_html/) or [Jupyter notebook](https://docs.marimo.io/guides/exporting/jupyter_notebook/) instead. Export from the marimo editor[¶](#export-from-the-marimo-editor "Permanent link") --------------------------------------------------------------------------------- Export from the notebook settings menu, in the top right. Download as static HTML. Export from the command line[¶](#export-from-the-command-line "Permanent link") ------------------------------------------------------------------------------- Export to markdown in top to bottom order, so the cells are in the order as they appear in the notebook. `[](#__codelineno-0-1)marimo export md notebook.py -o notebook.md` This can be useful to plug into other tools that read markdown, such as [Quarto](https://quarto.org/) or [MyST](https://myst-parser.readthedocs.io/). marimo can open markdown files as notebooks Learn more with `marimo tutorial markdown-format` at the command line. Convert markdown back to a marimo notebook[¶](#convert-markdown-back-to-a-marimo-notebook "Permanent link") ----------------------------------------------------------------------------------------------------------- You can also convert the markdown back to a marimo notebook: `[](#__codelineno-1-1)marimo convert notebook.md > notebook.py` WebAssembly HTML - marimo https://docs.marimo.io/guides/exporting/webassembly_html/ Export your notebook to a self-contained HTML file that runs using [WebAssembly](https://docs.marimo.io/guides/wasm/). Easiest way to share interactive notebooks For the simplest way to share interactive notebooks online, including WebAssembly notebooks, use [molab](https://docs.marimo.io/guides/molab/). `[](#__codelineno-0-1)# export as readonly, with code locked [](#__codelineno-0-2)marimo export html-wasm notebook.py -o output_dir --mode run [](#__codelineno-0-3)# export as an editable notebook [](#__codelineno-0-4)marimo export html-wasm notebook.py -o output_dir --mode edit` The exported HTML file will run your notebook using WebAssembly, making it completely self-contained and executable in the browser. This means users can interact with your notebook without needing Python or marimo installed. Options: * `--mode`: Choose between `run` (read-only) or `edit` (allows editing) * `--output`: Directory to save the HTML and required assets * `--show-code/--no-show-code`: Whether to initially show or hide the code in the notebook * `--watch/--no-watch`: Watch the notebook for changes and automatically export * `--include-cloudflare`: Write configuration files necessary for deploying to Cloudflare Note that WebAssembly notebooks have [limitations](https://docs.marimo.io/guides/wasm/#limitations); in particular, [many but not all packages work](https://docs.marimo.io/guides/wasm/#packages). Note The exported file must be served over HTTP to function correctly - it cannot be opened directly from the filesystem (`file://`). Your server must also serve the assets in the `assets` directory, next to the HTML file. For a simpler publishing experience, use [molab](https://docs.marimo.io/guides/molab/), publish to [GitHub Pages](https://docs.marimo.io/guides/publishing/github/#publish-to-github-pages), [Cloudflare](https://docs.marimo.io/guides/publishing/cloudflare/), or [self-host](https://docs.marimo.io/guides/publishing/self_host_wasm/). Deploying to Cloudflare You can include `--include-cloudflare` for deploying to Cloudflare. For example: `[](#__codelineno-1-1)marimo export html-wasm notebook.py -o my_app/dist --include-cloudflare` To run locally, run: To deploy to Cloudflare, run: Testing the export[¶](#testing-the-export "Permanent link") ----------------------------------------------------------- You can test the export by running the following command in the directory containing your notebook: `[](#__codelineno-4-1)cd path/to/output_dir [](#__codelineno-4-2)python -m http.server` Including data files[¶](#including-data-files "Permanent link") --------------------------------------------------------------- See the docs for [mo.notebook\_location](https://docs.marimo.io/api/miscellaneous/#marimo.notebook_location " marimo.notebook_location") to learn how to include data files in exported WASM HTML notebooks. Exporting multiple notebooks[¶](#exporting-multiple-notebooks "Permanent link") ------------------------------------------------------------------------------- In order to export multiple notebooks under the same folder, you can use the following snippet: `[](#__codelineno-5-1)files=("batch_and_form.py" "data_explorer.py") [](#__codelineno-5-2)[](#__codelineno-5-3)for file in "${files[@]}"; do [](#__codelineno-5-4) without_extension="${file%.*}" [](#__codelineno-5-5) marimo export html-wasm "$file" -o site/"$without_extension".html --mode run [](#__codelineno-5-6)done` Optionally, you can create an `index.html` file in the public directory: `[](#__codelineno-6-1)echo "" >> site/index.html` Embed marimo outputs in HTML using Islands[¶](#embed-marimo-outputs-in-html-using-islands "Permanent link") ----------------------------------------------------------------------------------------------------------- Preview Islands are an early feature. While the API likely won't change, there are some improvements we'd like to make before we consider them stable. Please let us know on [GitHub](https://github.com/marimo-team/marimo/issues) if you run into any issues or have any feedback! marimo islands are a way to embed marimo outputs and/or python code in your HTML that will become interactive when the page is loaded. This is useful for creating interactive blog posts, tutorials, and educational materials, all powered by marimo's reactive runtime. Check out an [example island-powered document](https://docs.marimo.io/guides/island_example/). ### Generating islands[¶](#generating-islands "Permanent link") Use `MarimoIslandGenerator` to generate HTML for islands Example From code blocksFrom notebook files `[](#__codelineno-7-1)import asyncio [](#__codelineno-7-2)import sys [](#__codelineno-7-3)from marimo import MarimoIslandGenerator [](#__codelineno-7-4)[](#__codelineno-7-5)if sys.platform == 'win32': [](#__codelineno-7-6) asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) [](#__codelineno-7-7)[](#__codelineno-7-8)async def main(): [](#__codelineno-7-9) generator = MarimoIslandGenerator() [](#__codelineno-7-10) block1 = generator.add_code("import marimo as mo") [](#__codelineno-7-11) block2 = generator.add_code("mo.md('Hello, islands!')") [](#__codelineno-7-12) [](#__codelineno-7-13) # Build the app [](#__codelineno-7-14) app = await generator.build() [](#__codelineno-7-15) [](#__codelineno-7-16) # Render the app [](#__codelineno-7-17) output = f""" [](#__codelineno-7-18) [](#__codelineno-7-19) [](#__codelineno-7-20) {generator.render_head()} [](#__codelineno-7-21) [](#__codelineno-7-22) [](#__codelineno-7-23) {block1.render(display_output=False)} [](#__codelineno-7-24) {block2.render()} [](#__codelineno-7-25) [](#__codelineno-7-26) [](#__codelineno-7-27) """ [](#__codelineno-7-28) print(output) [](#__codelineno-7-29) # Save the HTML to a file [](#__codelineno-7-30) output_file = "output.html" [](#__codelineno-7-31) with open(output_file, "w", encoding="utf-8") as f: [](#__codelineno-7-32) f.write(output) [](#__codelineno-7-33)[](#__codelineno-7-34)if __name__ == '__main__': [](#__codelineno-7-35) asyncio.run(main())` `[](#__codelineno-8-1)from marimo import MarimoIslandGenerator [](#__codelineno-8-2)[](#__codelineno-8-3)# Create the generator from file [](#__codelineno-8-4)generator = MarimoIslandGenerator.from_file("./.py", display_code=False) [](#__codelineno-8-5)[](#__codelineno-8-6)# Generate and print the HTML without building [](#__codelineno-8-7)# This will still work for basic rendering, though without running the cells [](#__codelineno-8-8)html = generator.render_html(include_init_island=False) [](#__codelineno-8-9)print(html) [](#__codelineno-8-10)# Save the HTML to a file [](#__codelineno-8-11)output_file = "output.html" [](#__codelineno-8-12)with open(output_file, "w", encoding="utf-8") as f: [](#__codelineno-8-13) f.write(html)` Any relevant `.html` that gets generated can be run through the [`development.md`](https://github.com/marimo-team/marimo/blob/main/frontend/islands/development.md) file instructions. ### Islands in action[¶](#islands-in-action "Permanent link") Advanced topic! Islands are an advanced concept that is meant to be a building block for creating integrations with existing tools such as static site generators or documentation tools. In order to use marimo islands, you need to import the necessary JS/CSS headers in your HTML file, and use our custom HTML tags to define the islands. `[](#__codelineno-9-1) [](#__codelineno-9-2) [](#__codelineno-9-10) [](#__codelineno-9-11) [](#__codelineno-9-12) [](#__codelineno-9-16) [](#__codelineno-9-22) [](#__codelineno-9-23)[](#__codelineno-9-24) [](#__codelineno-9-25) [](#__codelineno-9-26) [](#__codelineno-9-27) [](#__codelineno-9-28) Hello, islands! [](#__codelineno-9-29) [](#__codelineno-9-30) [](#__codelineno-9-31) [](#__codelineno-9-32) [](#__codelineno-9-33)` marimo.MarimoIslandGenerator [¶](#marimo.MarimoIslandGenerator "Permanent link") -------------------------------------------------------------------------------- `[](#__codelineno-0-1)MarimoIslandGenerator(app_id: str = 'main')` Generates Marimo islands for embedding in other pages. This is a great way to use another SSG framework that converts Python code to HTML using marimo-islands. Generally you will want to: 1. Find all the code snippets and add them to the generator. 2. Build the app. 3. Replace all code snippets with the rendered HTML. 4. Include the header in the tag. Examples: Using the MarimoIslandGenerator class: `[](#__codelineno-0-1)import asyncio [](#__codelineno-0-2)import sys [](#__codelineno-0-3)from marimo import MarimoIslandGenerator [](#__codelineno-0-4)[](#__codelineno-0-5)async def main(): [](#__codelineno-0-6) generator = MarimoIslandGenerator() [](#__codelineno-0-7) block1 = generator.add_code("import marimo as mo") [](#__codelineno-0-8) block2 = generator.add_code("mo.md('Hello, islands!')") [](#__codelineno-0-9) [](#__codelineno-0-10) # Build the app [](#__codelineno-0-11) app = await generator.build() [](#__codelineno-0-12) [](#__codelineno-0-13) # Render the app [](#__codelineno-0-14) output = f""" [](#__codelineno-0-15) [](#__codelineno-0-16) [](#__codelineno-0-17) {generator.render_head()} [](#__codelineno-0-18) [](#__codelineno-0-19) [](#__codelineno-0-20) {block1.render(display_output=False)} [](#__codelineno-0-21) {block2.render()} [](#__codelineno-0-22) [](#__codelineno-0-23) [](#__codelineno-0-24) """ [](#__codelineno-0-25) print(output) [](#__codelineno-0-26) # Save the HTML to a file [](#__codelineno-0-27) output_file = "output.html" [](#__codelineno-0-28) with open(output_file, "w", encoding="utf-8") as f: [](#__codelineno-0-29) f.write(output) [](#__codelineno-0-30)[](#__codelineno-0-31)if __name__ == '__main__': [](#__codelineno-0-32) asyncio.run(main())` You can also create the generator from a file: `[](#__codelineno-1-1)from marimo import MarimoIslandGenerator [](#__codelineno-1-2)[](#__codelineno-1-3)# Create the generator from file [](#__codelineno-1-4)generator = MarimoIslandGenerator.from_file( [](#__codelineno-1-5) "./.py", display_code=False [](#__codelineno-1-6)) [](#__codelineno-1-7)[](#__codelineno-1-8)# Generate and print the HTML without building [](#__codelineno-1-9)# This will still work for basic rendering, though without running the cells [](#__codelineno-1-10)html = generator.render_html(include_init_island=False) [](#__codelineno-1-11)print(html) [](#__codelineno-1-12)# Save the HTML to a file [](#__codelineno-1-13)output_file = "output.html" [](#__codelineno-1-14)with open(output_file, "w", encoding="utf-8") as f: [](#__codelineno-1-15) f.write(html)` | PARAMETER | DESCRIPTION | | --- | --- | | `app_id` | The optional identifier of the app, defaults to `main`. **TYPE:** `str` **DEFAULT:** `'main'` | ### has\_run `instance-attribute` [¶](#marimo.MarimoIslandGenerator.has_run "Permanent link") ### add\_code [¶](#marimo.MarimoIslandGenerator.add_code "Permanent link") `[](#__codelineno-0-1)add_code( [](#__codelineno-0-2) code: str, [](#__codelineno-0-3) display_code: bool = False, [](#__codelineno-0-4) display_output: bool = True, [](#__codelineno-0-5) is_reactive: bool = True, [](#__codelineno-0-6) is_raw: bool = False, [](#__codelineno-0-7)) -> MarimoIslandStub` Add a code cell to the app. _Args:_ * code (str): The code to add to the app. * display\_code (bool): Whether to display the code in the HTML. * display\_output (bool): Whether to display the output in the HTML. * is\_raw (bool): Whether to handled the code without formatting. * is\_reactive (bool): Whether this code block will run with pyodide. ### build `async` [¶](#marimo.MarimoIslandGenerator.build "Permanent link") Build the app. This should be called after adding all the code cells. _Returns:_ * App: The built app. ### from\_file `staticmethod` [¶](#marimo.MarimoIslandGenerator.from_file "Permanent link") `[](#__codelineno-0-1)from_file( [](#__codelineno-0-2) filename: str, display_code: bool = False [](#__codelineno-0-3)) -> [MarimoIslandGenerator](#marimo.MarimoIslandGenerator " marimo.MarimoIslandGenerator (marimo._islands._island_generator.MarimoIslandGenerator)")` Create a MarimoIslandGenerator and populate MarimoIslandStubs using code cells from a marimo \*.py file. _Args:_ * filename (str): Marimo .py filename to convert to reactive HTML. * display\_code (bool): Whether to display the code in HTML snippets. ### render\_body [¶](#marimo.MarimoIslandGenerator.render_body "Permanent link") `[](#__codelineno-0-1)render_body( [](#__codelineno-0-2) *, [](#__codelineno-0-3) include_init_island: bool = True, [](#__codelineno-0-4) max_width: str | None = None, [](#__codelineno-0-5) margin: str | None = None, [](#__codelineno-0-6) style: str | None = None, [](#__codelineno-0-7)) -> str` Render the body for the app. This should be included in the tag of the page. _Args:_ - include\_init\_island (bool): If True, adds initialization loader. - max\_width (str): CSS style max\_width property. - margin (str): CSS style margin property. - style (str): CSS style. Overrides max\_width and margin. ### render\_head [¶](#marimo.MarimoIslandGenerator.render_head "Permanent link") `[](#__codelineno-0-1)render_head( [](#__codelineno-0-2) *, [](#__codelineno-0-3) version_override: str = __version__, [](#__codelineno-0-4) _development_url: str | bool = False, [](#__codelineno-0-5)) -> str` Render the header for the app. This should be included in the tag of the page. _Args:_ * version\_override (str): Marimo version to use for loaded js/css. * \_development\_url (str): If True, uses local marimo islands js. ### render\_html [¶](#marimo.MarimoIslandGenerator.render_html "Permanent link") `[](#__codelineno-0-1)render_html( [](#__codelineno-0-2) *, [](#__codelineno-0-3) version_override: str = __version__, [](#__codelineno-0-4) _development_url: str | bool = False, [](#__codelineno-0-5) include_init_island: bool = True, [](#__codelineno-0-6) max_width: str | None = None, [](#__codelineno-0-7) margin: str | None = None, [](#__codelineno-0-8) style: str | None = None, [](#__codelineno-0-9)) -> str` Render reactive html for the app. _Args:_ * version\_override (str): Marimo version to use for loaded js/css. * \_development\_url (str): If True, uses local marimo islands js. * include\_init\_island (bool): If True, adds initialization loader. * max\_width (str): CSS style max\_width property. * margin (str): CSS style margin property. * style (str): CSS style. Overrides max\_width and margin. ### render\_init\_island [¶](#marimo.MarimoIslandGenerator.render_init_island "Permanent link") `[](#__codelineno-0-1)render_init_island() -> str` Renders a static html MarimoIsland str which displays a spinning initialization loader while Pyodide loads and disappears once the kernel is ready to use. Session snapshots - marimo https://docs.marimo.io/guides/exporting/sessions/ Run notebooks and write their serialized session snapshots. Export from the command line[¶](#export-from-the-command-line "Permanent link") ------------------------------------------------------------------------------- `[](#__codelineno-0-1)marimo export session notebook.py` By default, snapshots are written to: `[](#__codelineno-1-1)/__marimo__/session/.json` For example, exporting `notebook.py` writes: `[](#__codelineno-2-1)__marimo__/session/notebook.py.json` Export a directory[¶](#export-a-directory "Permanent link") ----------------------------------------------------------- `marimo export session` accepts one positional target: a notebook file or a directory. To process multiple notebooks, pass a directory target. Export every notebook in a directory: `[](#__codelineno-3-1)marimo export session folder/` Passing CLI args[¶](#passing-cli-args "Permanent link") ------------------------------------------------------- Pass CLI args through to notebooks with `--`: `[](#__codelineno-4-1)marimo export session notebook.py -- --foo 123` Staleness and force overwrite[¶](#staleness-and-force-overwrite "Permanent link") --------------------------------------------------------------------------------- By default, marimo only rewrites session snapshots when they are stale (for example, when notebook code changes or PEP 723 script metadata changes). Up-to-date snapshots are skipped. To force rewriting all snapshots, even when they are up-to-date: `[](#__codelineno-5-1)marimo export session folder/ --force-overwrite` Error handling[¶](#error-handling "Permanent link") --------------------------------------------------- If one notebook fails, marimo continues by default and exits non-zero after processing all targets. Use `--no-continue-on-error` to stop at the first failure. Sandboxed execution[¶](#sandboxed-execution "Permanent link") ------------------------------------------------------------- To execute in a sandboxed environment, pass `--sandbox`: `[](#__codelineno-6-1)marimo export session notebook.py --sandbox` Publish to the web - marimo https://docs.marimo.io/guides/publishing/ You can publish [exported](https://docs.marimo.io/guides/exporting/) marimo notebooks to the web. molab (recommended)[¶](#molab-recommended "Permanent link") ----------------------------------------------------------- The easiest way to publish and share interactive notebooks is with [molab](https://molab.marimo.io/notebooks), our free cloud-hosted notebook environment. With molab, you can: * Share notebooks by links * [Preview notebooks from GitHub](https://docs.marimo.io/guides/molab/#preview-notebooks-from-github) with full interactivity * Share [open-in-molab badges](https://docs.marimo.io/guides/molab/#share-open-in-molab-badges) in READMEs and docs * [Embed interactive notebooks](https://docs.marimo.io/guides/molab/#embed-in-other-webpages) in your own webpages * Contribute to our [public gallery](https://docs.marimo.io/guides/publishing/public_gallery/) Self-hosted options[¶](#self-hosted-options "Permanent link") ------------------------------------------------------------- If you need to self-host exported notebooks, the following guides cover publishing with [WebAssembly](https://docs.marimo.io/guides/wasm/) — no backend infrastructure required. | Guide | Description | | --- | --- | | [GitHub](https://docs.marimo.io/guides/publishing/github/) | Share from GitHub, view outputs, publish to GitHub Pages | | [Embed in other webpages](https://docs.marimo.io/guides/publishing/embedding/) | Embed notebooks in other sites via iframes or islands | | [Cloudflare](https://docs.marimo.io/guides/publishing/cloudflare/) | Publish interactive notebooks on Cloudflare | | [Self-host WebAssembly notebooks](https://docs.marimo.io/guides/publishing/self_host_wasm/) | Self-hosting interactive WebAssembly (HTML export) notebooks | | [OpenGraph previews](https://docs.marimo.io/guides/publishing/opengraph/) | Configure titles, descriptions, and thumbnails for link previews | | [Thumbnails](https://docs.marimo.io/guides/publishing/thumbnails/) | Generate thumbnail images for OpenGraph previews and galleries | Public gallery - marimo https://docs.marimo.io/guides/publishing/public_gallery/ Publish notebooks to the marimo gallery[¶](#publish-notebooks-to-the-marimo-gallery "Permanent link") ----------------------------------------------------------------------------------------------------- The [marimo gallery](https://marimo.io/gallery) showcases the best notebooks from our team and community. To be considered for inclusion, share your [molab](https://docs.marimo.io/guides/molab/) notebook and tag us on [Twitter / X](https://twitter.com/marimo_io), [Bluesky](https://bsky.app/profile/marimo.io), [LinkedIn](https://www.linkedin.com/company/marimo-io), or [Reddit](https://reddit.com/r/marimo_notebook). Community authors are credited with a link back to their website. GitHub - marimo https://docs.marimo.io/guides/publishing/github/ marimo makes it very easy to share links to executable notebooks from notebooks hosted on GitHub. * [Share molab links](https://docs.marimo.io/guides/molab/#preview-notebooks-from-github) to obtain interactive previews of notebooks hosted on GitHub, no login required * Publish notebooks to [GitHub Pages](#publish-to-github-pages) You can share previews of any marimo notebook hosted on GitHub using [molab](https://docs.marimo.io/guides/molab/); these previews are publicly viewable, no login required. Simply replace `github.com` in your notebook's GitHub URL with `molab.marimo.io/github` to create a shareable preview link. For example: `[](#__codelineno-0-1)https://github.com/marimo-team/gallery-examples/blob/main/notebooks/math/cellular-automaton-art.py` becomes `[](#__codelineno-1-1)https://molab.marimo.io/github/marimo-team/gallery-examples/blob/main/notebooks/math/cellular-automaton-art.py` Previews are **static** by default. To make them **interactive**, append `/wasm` to the URL (the notebook must be [WebAssembly-compatible](https://docs.marimo.io/guides/wasm/)). To include outputs in static previews, commit the notebook's session JSON file (in the `__marimo__/session/` directory alongside the notebook). Generate it with: `[](#__codelineno-2-1)marimo export session notebook.py` You can also share links using our open-in-molab badge. For example: `[](#__codelineno-3-1)[![Open in molab](https://marimo.io/molab-shield.svg)](https://molab.marimo.io/github/marimo-team/gallery-examples/blob/main/notebooks/math/cellular-automaton-art.py/wasm)` becomes Visit [molab.marimo.io/github](https://molab.marimo.io/github) to automatically generate preview URLs and badges from GitHub links. For full details on previewing, embedding, and sharing, see the [molab guide](https://docs.marimo.io/guides/molab/#preview-notebooks-from-github). Export to ipynb to view on GitHub[¶](#export-to-ipynb-to-view-on-github "Permanent link") ----------------------------------------------------------------------------------------- marimo notebooks are stored as pure Python files, which works well with Git versioning and the broader Python ecosystem. However, this means you cannot preview outputs directly on GitHub like you can with Jupyter notebooks. To make outputs viewable on GitHub, you can configure marimo to automatically snapshot outputs to an `ipynb` file. We treat the ipynb as an artifact that combines your source code with rendered outputs. The snapshot is saved to a `__marimo__` directory alongside your notebook, which you can commit and push to GitHub. Enable snapshotting in the notebook settings menu via the gear icon in the top right corner: Publish to GitHub Pages[¶](#publish-to-github-pages "Permanent link") --------------------------------------------------------------------- > For a simpler solution, use [molab's built in GitHub previewer](https://docs.marimo.io/guides/molab/#preview-notebooks-from-github) You can publish executable notebooks to [GitHub Pages](https://pages.github.com/) for free, after exporting your notebook to a WebAssembly notebook. ### Export to WASM-powered HTML[¶](#export-to-wasm-powered-html "Permanent link") Export your notebook to a self-contained HTML file that runs using [WebAssembly](https://docs.marimo.io/guides/wasm/): Export as a readonly appExport as an editable notebook `[](#__codelineno-4-1)marimo export html-wasm notebook.py -o output_dir --mode run` `[](#__codelineno-5-1)marimo export html-wasm notebook.py -o output_dir --mode edit` See our [exporting guide](https://docs.marimo.io/guides/exporting/webassembly_html/) for the full documentation. ### Publish using GitHub Actions[¶](#publish-using-github-actions "Permanent link") Template repository Fork our [template repository](https://github.com/marimo-team/marimo-gh-pages-template) for deploying multiple notebooks to GitHub Pages. Once you have forked the repository, add your notebooks to the `notebooks` or `apps` directories, for editable or readonly respectively. Publish to GitHub Pages using the following GitHub Actions workflow, which will republish your notebook on git push. `[](#__codelineno-6-1)jobs: [](#__codelineno-6-2) build: [](#__codelineno-6-3) runs-on: ubuntu-latest [](#__codelineno-6-4) [](#__codelineno-6-5) steps: [](#__codelineno-6-6) # ... checkout and install dependencies [](#__codelineno-6-7) [](#__codelineno-6-8) - name: 📄 Export notebook [](#__codelineno-6-9) run: | [](#__codelineno-6-10) marimo export html-wasm notebook.py -o path/to/output --mode run [](#__codelineno-6-11) [](#__codelineno-6-12) - name: 📦 Upload Pages Artifact [](#__codelineno-6-13) uses: actions/upload-pages-artifact@v3 [](#__codelineno-6-14) with: [](#__codelineno-6-15) path: path/to/output [](#__codelineno-6-16) [](#__codelineno-6-17) deploy: [](#__codelineno-6-18) needs: build [](#__codelineno-6-19) runs-on: ubuntu-latest [](#__codelineno-6-20) environment: [](#__codelineno-6-21) name: github-pages [](#__codelineno-6-22) url: ${{ steps.deployment.outputs.page_url }} [](#__codelineno-6-23) [](#__codelineno-6-24) permissions: [](#__codelineno-6-25) pages: write [](#__codelineno-6-26) id-token: write [](#__codelineno-6-27) [](#__codelineno-6-28) steps: [](#__codelineno-6-29) - name: 🌐 Deploy to GitHub Pages [](#__codelineno-6-30) id: deployment [](#__codelineno-6-31) uses: actions/deploy-pages@v4 [](#__codelineno-6-32) with: [](#__codelineno-6-33) artifact_name: github-pages` ### Publish manually[¶](#publish-manually "Permanent link") You can also publish an exported notebook manually through your repository settings. Read [GitHub's documentation](https://docs.github.com/en/pages/getting-started-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site) to learn more. Make sure to [include a `.nojekyll` file](https://github.blog/news-insights/bypassing-jekyll-on-github-pages/) in root folder from which your site is built to prevent GitHub from interfering with your site. Cloudflare - marimo https://docs.marimo.io/guides/publishing/cloudflare/ Publish to Cloudflare[¶](#publish-to-cloudflare "Permanent link") ----------------------------------------------------------------- You can publish executable notebooks to [Cloudflare Workers](https://workers.cloudflare.com/) for free, after exporting your notebook to a WebAssembly notebook. Export to WASM-powered HTML[¶](#export-to-wasm-powered-html "Permanent link") ----------------------------------------------------------------------------- Export your notebook to a self-contained HTML file that runs using [WebAssembly](https://docs.marimo.io/guides/wasm/) with the flag `--include-cloudflare`: Export as a readonly appExport as an editable notebook `[](#__codelineno-0-1)marimo export html-wasm notebook.py -o output_dir --mode run --include-cloudflare` `[](#__codelineno-1-1)marimo export html-wasm notebook.py -o output_dir --mode edit --include-cloudflare` See our [exporting guide](https://docs.marimo.io/guides/exporting/webassembly_html/) for the full documentation. Publish to a Cloudflare Worker[¶](#publish-to-a-cloudflare-worker "Permanent link") ----------------------------------------------------------------------------------- When you use the `--include-cloudflare` flag, marimo creates two additional files in the parent directory of your output directory: * `index.js`: A simple Cloudflare Worker script that serves your static assets * `wrangler.jsonc`: Configuration for Cloudflare's Wrangler CLI To run locally, run: To deploy to Cloudflare, run: Need authentication or custom endpoints? You can modify the `index.js` to include authentication or custom endpoints. This allows you to: * Add authentication logic to protect your notebook * Create API endpoints that serve data from the same domain, avoiding CORS issues Publish to Cloudflare Pages using GitHub[¶](#publish-to-cloudflare-pages-using-github "Permanent link") ------------------------------------------------------------------------------------------------------- As an alternative to Cloudflare Workers, you can publish to Cloudflare Pages. To get started, create a new GitHub repository by visiting [repo.new](https://repo.new/) . After creating a new repository, go to your newly created project directory to prepare and push your local application to GitHub by running the following commands in your terminal: `[](#__codelineno-4-1)cd output_dir [](#__codelineno-4-2)git init [](#__codelineno-4-3)git remote add origin https://github.com// [](#__codelineno-4-4)git add . [](#__codelineno-4-5)git commit -m "Initial commit" [](#__codelineno-4-6)git branch -M main [](#__codelineno-4-7)git push -u origin main` To deploy your site to Pages: 1. Log in to the Cloudflare [Dashboard](https://dash.cloudflare.com/) and select your account. 2. In Account Home, select Workers & Pages > Create application > Pages > Connect to Git. 3. Select the new GitHub repository that you created and, in the Set up builds and deployments section, provide the following information: `[](#__codelineno-5-1)Project name output-dir [](#__codelineno-5-2)Production branch main [](#__codelineno-5-3)Framework preset None [](#__codelineno-5-4)Build command (optional) exit 0 [](#__codelineno-5-5)Build output directory /` 4. Save and Deploy Publish to Cloudflare Pages Manually[¶](#publish-to-cloudflare-pages-manually "Permanent link") ----------------------------------------------------------------------------------------------- To deploy your site to Pages: 1. Create zip of the folder "output\_dir" 2. Log in to the Cloudflare [Dashboard](https://dash.cloudflare.com/) and select your account. 3. In Account Home, select Workers & Pages > Create application > Pages > Upload asset. 4. Enter a project name then click Upload and select output\_dir.zip . 5. Save and Deploy Self-host WebAssembly notebooks - marimo https://docs.marimo.io/guides/publishing/self_host_wasm/ As an alternative to [GitHub Pages](https://docs.marimo.io/guides/publishing/github/#publish-to-github-pages), it is possible to self-host exported [WebAssembly notebooks](https://docs.marimo.io/guides/wasm/): * [Export to WASM HTML](https://docs.marimo.io/guides/exporting/webassembly_html/). * Serve the exported file over HTTP. * Serve the assets in the `assets` directory, next to the HTML file. * Possibly configure your web server to support serving `application/wasm/` files with the correct headers. Embed in other webpages - marimo https://docs.marimo.io/guides/publishing/embedding/ There are various ways to embed marimo notebooks in other webpages, such as web documentation, educational platforms, or static sites in general. molab (recommended)[¶](#molab-recommended "Permanent link") ----------------------------------------------------------- The easiest way to embed interactive notebooks is with [molab](https://docs.marimo.io/guides/molab/). Click the "Share" button on molab WebAssembly previews of [notebooks from GitHub](https://docs.marimo.io/guides/molab/#preview-notebooks-from-github) to get an iframe snippet you can copy into your own webpages; or, construct embeddable URLs [from notebook source code](https://docs.marimo.io/guides/molab/#embed-from-source-code). This is what we do throughout this documentation website. See the [molab embedding docs](https://docs.marimo.io/guides/molab/#embed-in-other-webpages) for a complete walkthrough, and the below for a a simple example. CodeLive Example `[](#__codelineno-0-1)` Self-hosted options[¶](#self-hosted-options "Permanent link") ------------------------------------------------------------- If you need to self-host, you can also embed notebooks by: * Hosting on [GitHub Pages](https://docs.marimo.io/guides/publishing/github/#publish-to-github-pages) or [self-hosting WASM HTML](https://docs.marimo.io/guides/publishing/self_host_wasm/), and iframing the published notebook. * Using [marimo islands](https://docs.marimo.io/guides/exporting/webassembly_html/#embed-marimo-outputs-in-html-using-islands) to embed individual cell outputs directly in your HTML pages. Iframe sandbox configuration[¶](#iframe-sandbox-configuration "Permanent link") ------------------------------------------------------------------------------- When embedding marimo notebooks in sandboxed iframes, proper configuration is essential for full functionality. marimo is designed to gracefully degrade when certain features are restricted, but understanding these requirements will help you provide the best experience. ### Required sandbox attributes[¶](#required-sandbox-attributes "Permanent link") For marimo to function properly in an iframe, you need this **minimum** sandbox attribute: `[](#__codelineno-1-1)` * **`allow-scripts`**: Required for JavaScript execution (essential for marimo to run) Basic Functionality With only `allow-scripts`, marimo will work but with limitations: WebSocket connections will function, but storage will be in-memory only (state resets on page reload), and clipboard access will use browser prompts instead of the clipboard API. ### Recommended sandbox attributes[¶](#recommended-sandbox-attributes "Permanent link") For the best user experience, include these additional attributes: `[](#__codelineno-2-1)` **Additional Attributes:** * **`allow-same-origin`**: Enables persistent storage (localStorage) and full clipboard API. Only use this if you trust the content of the iframe or the iframe URL is hosted on a different domain. * **`allow-downloads`**: Enables downloading notebook outputs, data exports, and screenshots * **`allow-popups`**: Allows opening links and notebooks in new tabs * **`allow-forms`**: Enables form submissions, required for interactive UI elements like `mo.ui.form` * **`allowfullscreen`** (attribute, not sandbox): Enables fullscreen mode for slides and outputs **Permission Policy:** * **`allow="microphone"`**: Required for `mo.ui.microphone()` widget functionality Security Considerations Only use `allow-same-origin` with trusted content or the iframe URL is hosted on a different domain. Combining `allow-scripts` and `allow-same-origin` allows the iframe to remove the sandbox attribute entirely, making the iframe as powerful as if it weren't sandboxed at all. ### Full example[¶](#full-example "Permanent link") A complete, copy-pasteable example with all recommended settings: `[](#__codelineno-3-1)` Thumbnails - marimo https://docs.marimo.io/guides/publishing/thumbnails/ Generate screenshot-based thumbnail images for notebooks, used by [OpenGraph previews](https://docs.marimo.io/guides/publishing/opengraph/) and cards in [gallery mode](https://docs.marimo.io/guides/apps/#gallery). `[](#__codelineno-0-1)marimo export thumbnail notebook.py` Output location[¶](#output-location "Permanent link") ----------------------------------------------------- By default, thumbnails are written to: `[](#__codelineno-1-1)/__marimo__/assets//opengraph.png` This is the default OpenGraph thumbnail path used by [OpenGraph previews](https://docs.marimo.io/guides/publishing/opengraph/). Requirements[¶](#requirements "Permanent link") ----------------------------------------------- Requires Playwright Thumbnail generation uses Playwright and Chromium: `[](#__codelineno-2-1)python -m pip install playwright [](#__codelineno-2-2)python -m playwright install chromium` Generate thumbnails[¶](#generate-thumbnails "Permanent link") ------------------------------------------------------------- You can generate a thumbnail for a single notebook: `[](#__codelineno-3-1)marimo export thumbnail notebook.py` Or generate thumbnails for all notebooks in a directory: `[](#__codelineno-4-1)marimo export thumbnail folder/` When you pass a directory, marimo scans it for marimo notebooks and skips non-notebook files (for example `README.md`). Execution modes[¶](#execution-modes "Permanent link") ----------------------------------------------------- By default, thumbnails are generated without executing the notebook (fast; no outputs). You can opt into execution if you want outputs included. No execution (default)Execute notebookExecute in a sandbox `[](#__codelineno-5-1)marimo export thumbnail notebook.py` `[](#__codelineno-6-1)marimo export thumbnail --execute notebook.py` `[](#__codelineno-7-1)marimo export thumbnail --execute --sandbox notebook.py` Requires uv `--sandbox` runs the notebook in an isolated environment and installs dependencies from inline script metadata (PEP 723). See [Inlining dependencies](https://docs.marimo.io/guides/package_management/inlining_dependencies/). Sandbox only applies with execution `--sandbox` requires `--execute`. In `--no-execute` mode, marimo does not run the notebook, so there are no dependencies to install. Including code In `--no-execute` mode, thumbnails always include code. When using `--execute`, add `--include-code` to show code alongside outputs. Overwriting and custom output paths[¶](#overwriting-and-custom-output-paths "Permanent link") --------------------------------------------------------------------------------------------- If a thumbnail already exists, marimo will skip it by default. To replace existing thumbnails: `[](#__codelineno-8-1)marimo export thumbnail --overwrite notebook.py` To write a thumbnail to a specific filename, use `--output` (single notebook only): `[](#__codelineno-9-1)marimo export thumbnail --output thumbnail.png notebook.py` Tuning quality[¶](#tuning-quality "Permanent link") --------------------------------------------------- For OpenGraph previews, the default viewport size is 1200x630. marimo also uses a default `--scale 2` so thumbnails are crisp at typical OpenGraph resolutions. To increase output resolution, increase `--scale` (max 4): `[](#__codelineno-10-1)marimo export thumbnail --scale 3 notebook.py` If thumbnails appear blank or partially rendered, increase `--timeout-ms` to wait longer before the screenshot: `[](#__codelineno-11-1)marimo export thumbnail --timeout-ms 3000 notebook.py` Passing arguments to notebooks[¶](#passing-arguments-to-notebooks "Permanent link") ----------------------------------------------------------------------------------- To pass CLI args through to the notebook, separate them with `--`: `[](#__codelineno-12-1)marimo export thumbnail notebook.py -- --foo 123` For more on passing values to notebooks, see [Command Line Arguments](https://docs.marimo.io/api/cli_args/). OpenGraph previews - marimo https://docs.marimo.io/guides/publishing/opengraph/ marimo can attach OpenGraph metadata to notebooks for: * previews in the `marimo run ` [gallery](https://docs.marimo.io/guides/apps/#gallery) * link previews (OpenGraph tags in the notebook HTML) You configure this metadata in your notebook file using inline script metadata (PEP 723), under `[tool.marimo.opengraph]`. Add an `[tool.marimo.opengraph]` section to your script metadata: `[](#__codelineno-0-1)# /// script [](#__codelineno-0-2)# [tool.marimo.opengraph] [](#__codelineno-0-3)# title = "My notebook" [](#__codelineno-0-4)# description = "An interactive marimo app." [](#__codelineno-0-5)# ///` Available fields: * `title`: Title used in previews (defaults to a title-cased filename). * `description`: Short description shown in previews. * `image`: Optional thumbnail image. Must be either: * an HTTPS URL, or * a notebook-relative path under `__marimo__/` (for example, `__marimo__/assets/my_notebook/opengraph.png`). If you generate thumbnails to the default location (see below), you typically do not need to set `image`: marimo will automatically use `__marimo__/assets//opengraph.png` when it exists. Relative image paths For security, marimo only serves notebook-relative `image` paths from the notebook's `__marimo__/` directory. Thumbnails[¶](#thumbnails "Permanent link") ------------------------------------------- If you do not provide an `image`, marimo can still serve a deterministic placeholder thumbnail. If a screenshot-based thumbnail exists at the default location, marimo will automatically use it. The default thumbnail location is: `[](#__codelineno-1-1)__marimo__/assets//opengraph.png` To generate these thumbnails, use: `[](#__codelineno-2-1)marimo export thumbnail notebook.py [](#__codelineno-2-2)marimo export thumbnail folder/` For execution and sandbox options (and for Playwright installation instructions), see [Thumbnails](https://docs.marimo.io/guides/publishing/thumbnails/). For dynamic previews, you can provide a generator function in script metadata. Generators must be [top-level functions](https://docs.marimo.io/guides/reusing_functions/) (decorated with `@app.function`) and cannot depend on values defined in regular cells, so that they can be safely executed in the marimo CLI without running the whole notebook. In script metadata, point `generator` at the name of a function defined in the notebook: `[](#__codelineno-3-1)# /// script [](#__codelineno-3-2)# [tool.marimo.opengraph] [](#__codelineno-3-3)# description = "This description is static." [](#__codelineno-3-4)# generator = "generate_opengraph" [](#__codelineno-3-5)# ///` Then define the generator in a notebook cell: The generator return value is merged on top of the resolved "parent" metadata (declared fields + defaults). Any fields not returned by the generator are inherited from `parent`. ### Generator signatures[¶](#generator-signatures "Permanent link") The generator may accept 0, 1, or 2 positional arguments: * `generate_opengraph()` * `generate_opengraph(context)` * `generate_opengraph(context, parent)` Type hints: * `context`: `marimo._metadata.opengraph.OpenGraphContext` * `parent`: `marimo._metadata.opengraph.OpenGraphMetadata` `context` is an object with useful runtime information: * `context.filepath`: absolute path to the notebook * `context.file_key`: file router key (often a workspace-relative path) * `context.base_url`: server base URL (when running with `marimo run`) * `context.mode`: `"run"` or `"edit"` The generator may return: * an `OpenGraphMetadata` instance * a `dict` with any of `title`, `description`, and `image` * `None` (to leave the parent metadata unchanged) Deploy notebooks - marimo https://docs.marimo.io/guides/deploying/ Deploy notebook servers or apps[¶](#deploy-notebook-servers-or-apps "Permanent link") ------------------------------------------------------------------------------------- marimo can be deployed as an "edit" server for creating, running, and editing notebooks, or an app server for serving read-only web apps. For convenience, you can use our [pre-built containers](https://docs.marimo.io/guides/deploying/prebuilt_containers/). Sharing notebooks on the public web To share notebooks on the public web without managing infrastructure, try [molab](https://docs.marimo.io/guides/molab/), our free cloud-hosted notebook environment Notebook servers[¶](#notebook-servers "Permanent link") ------------------------------------------------------- Deploy an edit server (`marimo edit`) to let users create and edit notebooks on a remote instance. | Guide | Description | | --- | --- | | [JupyterHub](https://docs.marimo.io/guides/deploying/jupyterhub/) | Run marimo inside JupyterHub with our JupyterLab extension | | [Kubernetes](https://docs.marimo.io/guides/deploying/deploying_kubernetes/) | Deploy on Kubernetes | | [SkyPilot](https://docs.marimo.io/guides/deploying/deploying_skypilot/) | Deploy on cloud VMs with SkyPilot | | [Slurm](https://docs.marimo.io/guides/deploying/deploying_slurm/) | Run on HPC clusters with Slurm | You can also deploy an edit server with [ssh port forwarding](https://docs.marimo.io/faq/#faq-remote) using `marimo edit --headless`. Apps[¶](#apps "Permanent link") ------------------------------- Deploy notebooks as read-only web apps (`marimo run`) or embed them in other applications. | Guide | Description | | --- | --- | | [FastAPI](https://docs.marimo.io/guides/deploying/programmatically/) | Programmatically run marimo apps as part of ASGI applications | | [Authentication](https://docs.marimo.io/guides/deploying/authentication/) | Authentication and security | | [Docker](https://docs.marimo.io/guides/deploying/deploying_docker/) | Deploy with Docker | | [HuggingFace](https://docs.marimo.io/guides/deploying/deploying_hugging_face/) | Deploy to Hugging Face Spaces | | [Railway](https://docs.marimo.io/guides/deploying/deploying_railway/) | Deploy to Railway | | [nginx](https://docs.marimo.io/guides/deploying/deploying_nginx/) | Deploy behind nginx | ### Health and status endpoints[¶](#health-and-status-endpoints "Permanent link") The following endpoints may be useful when deploying your application: * `/health` - A health check endpoint that returns a 200 status code if the application is running as expected * `/healthz` - Same as above, just a different name for easier integration with cloud providers * `/api/status` - A status endpoint that returns a JSON object with the status of the server ### Configuration[¶](#configuration "Permanent link") If you would like to deploy your application at a subpath, you can set the `--base-url` flag when running your application. `[](#__codelineno-0-1)marimo run app.py --base-url /subpath` ### Including code in your application[¶](#including-code-in-your-application "Permanent link") You can include code in your application by using the `--include-code` flag when running your application. `[](#__codelineno-1-1)marimo run app.py --include-code` ### Redirecting standard output to the browser[¶](#redirecting-standard-output-to-the-browser "Permanent link") By default, Marimo doesn't send standard output (stdout) to the browser, but for debugging purposes you can enable this with `--redirect-console-to-browser`: `[](#__codelineno-2-1)marimo run app.py --redirect-console-to-browser` ### Showing error tracebacks in the browser[¶](#showing-error-tracebacks-in-the-browser "Permanent link") By default, Marimo redacts error tracebacks in the browser for security reasons, but you can enable showing full tracebacks with `--show-tracebacks`: `[](#__codelineno-3-1)marimo run app.py --show-tracebacks` Prebuilt containers - marimo https://docs.marimo.io/guides/deploying/prebuilt_containers/ marimo provides prebuilt containers for running a marimo server. You can find the containers and tags on [marimo's GitHub packages page](https://github.com/marimo-team/marimo/pkgs/container/marimo). We provide the following variants: * `marimo:latest` - The latest version of marimo * `marimo:latest-data` - The latest version of marimo with `marimo[recommended,lsp]`, `altair`, `pandas`, and `numpy` preinstalled. * `marimo:latest-sql` - The latest version of marimo with `marimo[recommended,lsp,sql]` preinstalled. or any particular version of marimo; for example, `marimo:0.8.3`, `marimo:0.8.3-data`, `marimo:0.8.3-sql`. Each container is built on `3.13-slim`, but if you'd like to see different configurations, please file an issue or submit a PR! Running locally[¶](#running-locally "Permanent link") ----------------------------------------------------- To run the container locally, you can use the following command: `[](#__codelineno-0-1)docker run -p 8080:8080 -it ghcr.io/marimo-team/marimo:latest-sql` Use in a Dockerfile[¶](#use-in-a-dockerfile "Permanent link") ------------------------------------------------------------- To use a prebuilt container in a Dockerfile, you can use the following command: `[](#__codelineno-1-1)FROM ghcr.io/marimo-team/marimo:latest-sql [](#__codelineno-1-2)[](#__codelineno-1-3)# Install any additional dependencies here [](#__codelineno-1-4)[](#__codelineno-1-5)CMD ["marimo", "edit", "--no-token", "-p", "8080", "--host", "0.0.0.0"]` JupyterHub - marimo https://docs.marimo.io/guides/deploying/jupyterhub/ > For full documentation, visit the [marimo-jupyter-extension repository](https://github.com/marimo-team/marimo-jupyter-extension). The [marimo JupyterLab extension](https://github.com/marimo-team/marimo-jupyter-extension) integrates marimo into JupyterLab and JupyterHub, letting you launch marimo notebooks directly from JupyterLab's launcher, manage running sessions, and convert Jupyter notebooks to marimo format. marimo running in a JupyterHub deployment, in JupyterLab. Features[¶](#features "Permanent link") --------------------------------------- * **Launcher integration**: marimo appears in the JupyterLab launcher with its own icon * **First-class notebook support**: double-click `_mo.py` files to open directly in marimo * **Sidebar panel**: monitor server status, view running sessions with kill buttons, and access quick actions * **Environment selection**: choose from available Python environments when creating notebooks; the extension discovers Jupyter kernel specs, letting you use your own venvs or conda environments. * **Context menus**: right-click `.py` files to edit with marimo, or `.ipynb` files to convert to marimo format * **Sandbox mode**: run marimo in isolated environments with `uvx` ### File type handling[¶](#file-type-handling "Permanent link") | File Type | Double-click | Right-click | | --- | --- | --- | | `_mo.py` | Opens in marimo | "Edit with marimo" | | `.py` | Opens in standard editor | "Edit with marimo" | | `.ipynb` | Opens in Jupyter | "Convert to marimo" | Installation[¶](#installation "Permanent link") ----------------------------------------------- ### Single environment[¶](#single-environment "Permanent link") `[](#__codelineno-0-1)uv pip install 'marimo[sandbox]>=0.19.11' marimo-jupyter-extension` ### JupyterHub (multiple environments)[¶](#jupyterhub-multiple-environments "Permanent link") | Package | Install location | Why | | --- | --- | --- | | `marimo` | User's environment | Access user's packages | | `marimo-jupyter-extension` | Jupyter's environment | Jupyter must import it | Configuration[¶](#configuration "Permanent link") ------------------------------------------------- Configure the extension in `jupyterhub_config.py`: `[](#__codelineno-1-1)# Explicit marimo path [](#__codelineno-1-2)c.MarimoProxyConfig.marimo_path = "/opt/bin/marimo" [](#__codelineno-1-3)[](#__codelineno-1-4)# Or use uvx mode (sandbox) [](#__codelineno-1-5)c.MarimoProxyConfig.uvx_path = "/usr/local/bin/uvx" [](#__codelineno-1-6)[](#__codelineno-1-7)# Startup timeout (default: 60s) [](#__codelineno-1-8)c.MarimoProxyConfig.timeout = 120` Troubleshooting[¶](#troubleshooting "Permanent link") ----------------------------------------------------- | Issue | Solution | | --- | --- | | marimo icon missing | Install `marimo-jupyter-extension` in Jupyter's environment | | marimo fails to launch | Ensure marimo is in PATH or configure `MarimoProxyConfig.marimo_path` | | Modules not found | Install marimo in the same environment as your packages | | Sandbox features not working | Upgrade to `marimo[sandbox]>=0.19.11` | For more troubleshooting tips, see the [full documentation](https://github.com/marimo-team/marimo-jupyter-extension). Kubernetes - marimo https://docs.marimo.io/guides/deploying/deploying_kubernetes/ Deploy with Kubernetes[¶](#deploy-with-kubernetes "Permanent link") ------------------------------------------------------------------- The [marimo-operator](https://github.com/marimo-team/marimo-operator) is a Kubernetes operator that manages marimo notebook deployments. It handles persistent storage, resource allocation, and lifecycle management for notebooks running on Kubernetes clusters. Quick start For the fastest path to running notebooks on Kubernetes, use the `kubectl-marimo` CLI plugin. It handles manifest generation, port forwarding, and file synchronization automatically. Prerequisites[¶](#prerequisites "Permanent link") ------------------------------------------------- * Kubernetes cluster (v1.25+) * `kubectl` configured with cluster access * Python 3.9+ with `pip` or `uv` * Cluster admin permissions (for initial operator installation) Install the operator[¶](#install-the-operator "Permanent link") --------------------------------------------------------------- Install the marimo operator on your cluster: `[](#__codelineno-0-1)kubectl apply -f https://raw.githubusercontent.com/marimo-team/marimo-operator/main/deploy/install.yaml` Verify the operator is running: `[](#__codelineno-1-1)kubectl get pods -n marimo-operator-system` The output should show the operator pod running: `[](#__codelineno-2-1)NAME READY STATUS RESTARTS AGE [](#__codelineno-2-2)marimo-operator-controller-manager-xxxxx 1/1 Running 0 30s` Quickstart with kubectl-marimo[¶](#quickstart-with-kubectl-marimo "Permanent link") ----------------------------------------------------------------------------------- The `kubectl-marimo` plugin is the recommended way to deploy notebooks from local files. ### Install the plugin[¶](#install-the-plugin "Permanent link") `[](#__codelineno-3-1)# With uv (recommended) [](#__codelineno-3-2)uv tool install kubectl-marimo [](#__codelineno-3-3)[](#__codelineno-3-4)# Or with pip [](#__codelineno-3-5)pip install kubectl-marimo` ### Run a notebook[¶](#run-a-notebook "Permanent link") Edit a notebook interactively on the cluster: `[](#__codelineno-4-1)kubectl marimo edit notebook.py` This command: 1. Uploads your notebook to the cluster 2. Creates persistent storage for your changes 3. Starts the marimo server 4. Sets up port forwarding to your local machine When you stop the command (`Ctrl+C`), it syncs changes back to your local file and tears down the pod. To run a notebook as a read-only application: `[](#__codelineno-5-1)kubectl marimo run notebook.py` ### Configure resources[¶](#configure-resources "Permanent link") Configure your notebook's Kubernetes resources using frontmatter in your notebook file. **Python notebooks (.py):** `[](#__codelineno-6-1)# /// script [](#__codelineno-6-2)# requires-python = ">=3.12" [](#__codelineno-6-3)# dependencies = ["marimo", "pandas", "numpy"] [](#__codelineno-6-4)# [](#__codelineno-6-5)# [tool.marimo.k8s] [](#__codelineno-6-6)# image = "ghcr.io/marimo-team/marimo:latest" [](#__codelineno-6-7)# storage = "5Gi" [](#__codelineno-6-8)# [tool.marimo.k8s.resources] [](#__codelineno-6-9)# requests.cpu = "500m" [](#__codelineno-6-10)# requests.memory = "2Gi" [](#__codelineno-6-11)# limits.cpu = "2" [](#__codelineno-6-12)# limits.memory = "8Gi" [](#__codelineno-6-13)# ///` **Markdown notebooks (.md):** `[](#__codelineno-7-1)--- [](#__codelineno-7-2)title: my-analysis [](#__codelineno-7-3)image: ghcr.io/marimo-team/marimo:latest [](#__codelineno-7-4)storage: 5Gi [](#__codelineno-7-5)resources: [](#__codelineno-7-6) requests: [](#__codelineno-7-7) cpu: "500m" [](#__codelineno-7-8) memory: "2Gi" [](#__codelineno-7-9) limits: [](#__codelineno-7-10) cpu: "2" [](#__codelineno-7-11) memory: "8Gi" [](#__codelineno-7-12)---` ### Configuration fields[¶](#configuration-fields "Permanent link") | Field | Description | Default | | --- | --- | --- | | `title` | Resource name in Kubernetes | filename | | `image` | Container image | `ghcr.io/marimo-team/marimo:latest` | | `port` | Server port | 2718 | | `storage` | Persistent volume size | none (ephemeral) | | `resources` | CPU, memory, GPU requests/limits | none | | `auth` | Set to `"none"` to disable authentication | token auth | | `env` | Environment variables | none | ### Manage deployments[¶](#manage-deployments "Permanent link") `[](#__codelineno-8-1)# Sync changes back to local file [](#__codelineno-8-2)kubectl marimo sync notebook.py [](#__codelineno-8-3)[](#__codelineno-8-4)# Delete deployment [](#__codelineno-8-5)kubectl marimo delete notebook.py [](#__codelineno-8-6)[](#__codelineno-8-7)# List active deployments [](#__codelineno-8-8)kubectl marimo status` GPU workloads[¶](#gpu-workloads "Permanent link") ------------------------------------------------- Specify GPU resources in your notebook frontmatter: **Python notebooks:** `[](#__codelineno-9-1)# /// script [](#__codelineno-9-2)# [tool.marimo.k8s.resources] [](#__codelineno-9-3)# limits."nvidia.com/gpu" = 1 [](#__codelineno-9-4)# ///` **Markdown notebooks:** `[](#__codelineno-10-1)--- [](#__codelineno-10-2)resources: [](#__codelineno-10-3) limits: [](#__codelineno-10-4) nvidia.com/gpu: 1 [](#__codelineno-10-5)---` The Kubernetes scheduler will place your notebook on an appropriate GPU node. Cloud storage integration[¶](#cloud-storage-integration "Permanent link") ------------------------------------------------------------------------- The marimo operator supports mounting cloud storage (S3-compatible buckets, SSHFS, rsync) in your notebooks. See the [operator documentation](https://github.com/marimo-team/marimo-operator) for mount configuration details. Deploy with manifests[¶](#deploy-with-manifests "Permanent link") ----------------------------------------------------------------- For advanced users who need fine-grained control, you can create `MarimoNotebook` resources directly. ### Basic manifest[¶](#basic-manifest "Permanent link") `[](#__codelineno-11-1)apiVersion: marimo.io/v1alpha1 [](#__codelineno-11-2)kind: MarimoNotebook [](#__codelineno-11-3)metadata: [](#__codelineno-11-4) name: my-notebook [](#__codelineno-11-5)spec: [](#__codelineno-11-6) source: https://github.com/marimo-team/examples.git [](#__codelineno-11-7) storage: [](#__codelineno-11-8) size: 1Gi` Apply the manifest: `[](#__codelineno-12-1)kubectl apply -f notebook.yaml` Check the status: Port forward to access: `[](#__codelineno-14-1)kubectl port-forward svc/my-notebook 2718:2718` ### With GPU and sidecars[¶](#with-gpu-and-sidecars "Permanent link") `[](#__codelineno-15-1)apiVersion: marimo.io/v1alpha1 [](#__codelineno-15-2)kind: MarimoNotebook [](#__codelineno-15-3)metadata: [](#__codelineno-15-4) name: gpu-notebook [](#__codelineno-15-5)spec: [](#__codelineno-15-6) source: https://github.com/your-org/notebooks.git [](#__codelineno-15-7) storage: [](#__codelineno-15-8) size: 5Gi [](#__codelineno-15-9) resources: [](#__codelineno-15-10) requests: [](#__codelineno-15-11) memory: 4Gi [](#__codelineno-15-12) limits: [](#__codelineno-15-13) memory: 16Gi [](#__codelineno-15-14) nvidia.com/gpu: 1 [](#__codelineno-15-15) sidecars: [](#__codelineno-15-16) - name: ssh [](#__codelineno-15-17) image: linuxserver/openssh-server:latest [](#__codelineno-15-18) exposePort: 2222` Clean up[¶](#clean-up "Permanent link") --------------------------------------- `[](#__codelineno-16-1)# Via plugin (syncs changes first) [](#__codelineno-16-2)kubectl marimo delete notebook.py [](#__codelineno-16-3)[](#__codelineno-16-4)# Via kubectl (does not sync) [](#__codelineno-16-5)kubectl delete marimo my-notebook` Sync before deleting Using `kubectl delete` directly will **not** sync your changes back to your local file. Use `kubectl marimo delete` to automatically sync before deletion. Learn more[¶](#learn-more "Permanent link") ------------------------------------------- * [marimo-operator on GitHub](https://github.com/marimo-team/marimo-operator) * [SkyPilot deployment](https://docs.marimo.io/guides/deploying/deploying_skypilot/) - For multi-cloud VM deployment without Kubernetes * [Docker deployment](https://docs.marimo.io/guides/deploying/deploying_docker/) - For container basics * [Inlining dependencies](https://docs.marimo.io/guides/package_management/inlining_dependencies/) - For reproducible notebooks SkyPilot - marimo https://docs.marimo.io/guides/deploying/deploying_skypilot/ Deploy with SkyPilot[¶](#deploy-with-skypilot "Permanent link") --------------------------------------------------------------- [SkyPilot](https://skypilot.readthedocs.io/) is an open-source framework that allows you to run workloads on any cloud (AWS, GCP, Azure, Coreweave, and more) with a unified interface. It's particularly well-suited for running marimo notebooks on GPU instances for machine learning and data science workloads. New to SkyPilot? If you haven't used SkyPilot before, start with their [getting started guide](https://skypilot.readthedocs.io/en/latest/getting-started/installation.html) to install SkyPilot and set up cloud credentials. marimo notebooks work exceptionally well with SkyPilot because they are stored as pure Python scripts and can be run both interactively and as batch jobs. With marimo's built-in `uv` integration, your notebooks are fully reproducible across different environments. Interactive Development[¶](#interactive-development "Permanent link") --------------------------------------------------------------------- For interactive development with marimo on a SkyPilot cluster, you can launch a cluster and connect to it with SSH port forwarding. ### Launch a cluster[¶](#launch-a-cluster "Permanent link") First, create a cluster with your desired resources, ([see the guide](https://docs.skypilot.co/en/latest/getting-started/installation.html#set-up-kubernetes-or-clouds)): `[](#__codelineno-0-1)sky launch --gpus V100:1 -c dev` ### Connect with port forwarding[¶](#connect-with-port-forwarding "Permanent link") Connect to the cluster and forward the port that marimo will use: `[](#__codelineno-1-1)ssh -L 8080:localhost:8080 dev` ### Start marimo[¶](#start-marimo "Permanent link") Inside the cluster, install `uv` and start marimo with the `--sandbox` flag for isolated dependencies: `[](#__codelineno-2-1)pip install uv [](#__codelineno-2-2)uvx marimo edit --sandbox demo.py --port 8080 --token-password=supersecret` Sandboxed environments The `uvx` command runs marimo without installing it in your environment, and the `--sandbox` flag ensures that notebook dependencies are installed in a separate environment. This makes your development fully reproducible and isolated. See [inlining dependencies](https://docs.marimo.io/guides/package_management/inlining_dependencies/) for more on creating reproducible notebooks. You can now access your marimo notebook at `localhost:8080` in your local browser and authenticate with the password you set. Running as Batch Jobs[¶](#running-as-batch-jobs "Permanent link") ----------------------------------------------------------------- Because marimo notebooks are Python scripts, they can be submitted as managed SkyPilot jobs. This is useful for training models, running experiments, or processing data without needing an interactive session. ### Create a job-compatible notebook[¶](#create-a-job-compatible-notebook "Permanent link") marimo notebooks can accept command-line arguments using `mo.cli_args()`. Here's an example notebook that demonstrates this: `[](#__codelineno-3-1)# /// script [](#__codelineno-3-2)# requires-python = ">=3.12" [](#__codelineno-3-3)# dependencies = [ [](#__codelineno-3-4)# "marimo", [](#__codelineno-3-5)# ] [](#__codelineno-3-6)# /// [](#__codelineno-3-7)[](#__codelineno-3-8)import marimo [](#__codelineno-3-9)[](#__codelineno-3-10)__generated_with = "0.18.1" [](#__codelineno-3-11)app = marimo.App() [](#__codelineno-3-12) [](#__codelineno-3-13)[](#__codelineno-3-14)@app.cell [](#__codelineno-3-15)def _(): [](#__codelineno-3-16) import marimo as mo [](#__codelineno-3-17) return (mo,) [](#__codelineno-3-18) [](#__codelineno-3-19)[](#__codelineno-3-20)@app.cell [](#__codelineno-3-21)def _(mo): [](#__codelineno-3-22) # Parse command-line arguments [](#__codelineno-3-23) args = mo.cli_args() [](#__codelineno-3-24) print(f"Running with arguments: {args}") [](#__codelineno-3-25) return [](#__codelineno-3-26) [](#__codelineno-3-27)[](#__codelineno-3-28)if __name__ == "__main__": [](#__codelineno-3-29) app.run()` You can test this locally: `[](#__codelineno-4-1)uv run demo.py --hello world --demo works --lr 0.01` This will print: `[](#__codelineno-5-1){'hello': 'world', 'demo': 'works', 'lr': '0.01'}` ### Create a SkyPilot job configuration[¶](#create-a-skypilot-job-configuration "Permanent link") Create a YAML file to configure your job: `[](#__codelineno-6-1)# marimo-job.yaml [](#__codelineno-6-2)name: marimo-demo [](#__codelineno-6-3)[](#__codelineno-6-4)# Specify resources for this job [](#__codelineno-6-5)resources: [](#__codelineno-6-6) accelerators: V100:1 [](#__codelineno-6-7)[](#__codelineno-6-8)# Point to the folder containing your marimo notebook [](#__codelineno-6-9)workdir: . [](#__codelineno-6-10)[](#__codelineno-6-11)# Environment variables (e.g., for W&B, HuggingFace) [](#__codelineno-6-12)envs: [](#__codelineno-6-13) WANDB_API_KEY: ${WANDB_API_KEY} [](#__codelineno-6-14)[](#__codelineno-6-15)# Install uv [](#__codelineno-6-16)setup: pip install uv [](#__codelineno-6-17)[](#__codelineno-6-18)# Run the notebook with arguments [](#__codelineno-6-19)run: uv run demo.py --hello world --demo works --lr 0.01` ### Launch the job[¶](#launch-the-job "Permanent link") Submit the job to SkyPilot: `[](#__codelineno-7-1)sky jobs launch -n marimo-demo marimo-job.yaml` SkyPilot will provision cloud resources, run your notebook, and automatically tear down the resources after the job completes (with a configurable idle timeout). ### Monitor job progress[¶](#monitor-job-progress "Permanent link") You can monitor your job using: `[](#__codelineno-8-1)# View logs [](#__codelineno-8-2)sky jobs logs marimo-demo [](#__codelineno-8-3)[](#__codelineno-8-4)# Check job status [](#__codelineno-8-5)sky jobs queue [](#__codelineno-8-6)[](#__codelineno-8-7)# Launch dashboard [](#__codelineno-8-8)sky jobs dashboard` Benefits of marimo + SkyPilot[¶](#benefits-of-marimo-skypilot "Permanent link") ------------------------------------------------------------------------------- * **Reproducible**: marimo's `uv` integration ensures consistent dependency management * **Cost-effective**: SkyPilot finds the cheapest resources across clouds and automatically terminates idle instances * **Flexible**: Use the same notebook interactively or as a batch job * **Cloud-agnostic**: Run on any cloud provider without changing your code Multi-cloud setup[¶](#multi-cloud-setup "Permanent link") --------------------------------------------------------- SkyPilot supports AWS, GCP, Azure, Lambda Labs, and more. See their [cloud setup guide](https://skypilot.readthedocs.io/en/latest/getting-started/installation.html#cloud-account-setup) to configure credentials for your preferred cloud providers. Learn more[¶](#learn-more "Permanent link") ------------------------------------------- * [SkyPilot documentation](https://skypilot.readthedocs.io/) * [SkyPilot managed jobs guide](https://skypilot.readthedocs.io/en/latest/examples/managed-jobs.html) * [marimo CLI arguments](https://docs.marimo.io/api/cli_args/) FastAPI - marimo https://docs.marimo.io/guides/deploying/programmatically/ Running the marimo backend programmatically[¶](#running-the-marimo-backend-programmatically "Permanent link") ------------------------------------------------------------------------------------------------------------- marimo can be run programmatically using the `marimo` module. This is useful when you want to run marimo as part of a larger application or when you need to customize the behavior of marimo (e.g. middleware, custom error handling, authentication, routing, etc). FastAPI Example[¶](#fastapi-example "Permanent link") ----------------------------------------------------- Here's an example of how you can run a marimo application programmatically using FastAPI: `[](#__codelineno-0-1)from typing import Annotated, Callable, Coroutine [](#__codelineno-0-2)from fastapi.responses import HTMLResponse, RedirectResponse [](#__codelineno-0-3)import marimo [](#__codelineno-0-4)from fastapi import FastAPI, Form, Request, Response [](#__codelineno-0-5) [](#__codelineno-0-6)[](#__codelineno-0-7)# Create a marimo asgi app [](#__codelineno-0-8)server = ( [](#__codelineno-0-9) marimo.create_asgi_app() [](#__codelineno-0-10) .with_app(path="", root="./pages/index.py") [](#__codelineno-0-11) .with_app(path="/dashboard", root="./pages/dashboard.py") [](#__codelineno-0-12) .with_app(path="/sales", root="./pages/sales.py") [](#__codelineno-0-13)) [](#__codelineno-0-14)[](#__codelineno-0-15)# Create a FastAPI app [](#__codelineno-0-16)app = FastAPI() [](#__codelineno-0-17)[](#__codelineno-0-18)app.add_middleware(auth_middleware) [](#__codelineno-0-19)app.add_route("/login", my_login_route, methods=["POST"]) [](#__codelineno-0-20)[](#__codelineno-0-21)app.mount("/", server.build()) [](#__codelineno-0-22)[](#__codelineno-0-23)# Run the server [](#__codelineno-0-24)if __name__ == "__main__": [](#__codelineno-0-25) import uvicorn [](#__codelineno-0-26) [](#__codelineno-0-27) uvicorn.run(app, host="localhost", port=8000)` For a more complete example, see the [FastAPI example](https://github.com/marimo-team/marimo/tree/main/examples/frameworks/fastapi). Note that when run in this mode, marimo will serve its static assets under the name of the notebook (in the example above, that would be `http://hostname//assets/`). If you are using custom authorization middleware, skip authentication for these assets to avoid server round-trips. There are _many_ of them. Dynamic directory[¶](#dynamic-directory "Permanent link") --------------------------------------------------------- If you'd like to create a server to dynamically load marimo notebooks from a directory, you can use the `with_dynamic_directory` method. This is useful if the contents of the directory change often, such as a directory of notebooks for a dashboard, without restarting the server. `[](#__codelineno-1-1)server = ( [](#__codelineno-1-2) marimo.create_asgi_app() [](#__codelineno-1-3) .with_dynamic_directory(path="/dashboard", directory="./notebooks") [](#__codelineno-1-4))` If the notebooks in the directory are expected to be static, it is better to use the `with_app` method and loop through the directory contents. `[](#__codelineno-2-1)from pathlib import Path [](#__codelineno-2-2)server = marimo.create_asgi_app() [](#__codelineno-2-3)app_names: list[str] = [] [](#__codelineno-2-4)[](#__codelineno-2-5)notebooks_dir = Path(__file__).parent / "notebooks" [](#__codelineno-2-6)[](#__codelineno-2-7)for filename in sorted(notebooks_dir.iterdir()): [](#__codelineno-2-8) if filename.suffix == ".py": [](#__codelineno-2-9) app_name = filename.stem [](#__codelineno-2-10) server = server.with_app(path=f"/{app_name}", root=filename) [](#__codelineno-2-11) app_names.append(app_name)` Accessing Request Data[¶](#accessing-request-data "Permanent link") ------------------------------------------------------------------- Inside your marimo notebooks, you can access the current request data using `mo.app_meta().request`. This is particularly useful when implementing authentication or accessing user data. `[](#__codelineno-3-1)import marimo as mo [](#__codelineno-3-2)[](#__codelineno-3-3)# Access request data in your notebook [](#__codelineno-3-4)request = mo.app_meta().request [](#__codelineno-3-5)if request and request.user and request.user["is_authenticated"]: [](#__codelineno-3-6) content = f"Welcome {request.user['username']}!" [](#__codelineno-3-7)else: [](#__codelineno-3-8) content = "Please log in" [](#__codelineno-3-9)[](#__codelineno-3-10)mo.md(content)` ### Authentication Middleware Example[¶](#authentication-middleware-example "Permanent link") Here's an example of how to implement authentication middleware that populates `request.user`. Use a pure ASGI middleware Use a pure ASGI middleware (not Starlette's `BaseHTTPMiddleware`) so that `scope["user"]` and `scope["meta"]` are set for **both** HTTP and WebSocket connections. marimo uses WebSocket for real-time communication, and `BaseHTTPMiddleware` only runs for HTTP requests. `[](#__codelineno-4-1)class AuthMiddleware: [](#__codelineno-4-2) def __init__(self, app): [](#__codelineno-4-3) self.app = app [](#__codelineno-4-4) [](#__codelineno-4-5) async def __call__(self, scope, receive, send): [](#__codelineno-4-6) if scope["type"] in ("http", "websocket"): [](#__codelineno-4-7) # Add user data to the request scope [](#__codelineno-4-8) # This will be accessible via mo.app_meta().request.user [](#__codelineno-4-9) scope["user"] = { [](#__codelineno-4-10) "is_authenticated": True, [](#__codelineno-4-11) "username": "example_user", [](#__codelineno-4-12) # Add any other user data [](#__codelineno-4-13) } [](#__codelineno-4-14) # Optionally add metadata to the request [](#__codelineno-4-15) scope["meta"] = { [](#__codelineno-4-16) "some_key": "some_value", [](#__codelineno-4-17) } [](#__codelineno-4-18) await self.app(scope, receive, send) [](#__codelineno-4-19)[](#__codelineno-4-20)# Add the middleware to your FastAPI app [](#__codelineno-4-21)app.add_middleware(AuthMiddleware)` The `request` object provides access to: * `request.headers`: Request headers * `request.cookies`: Request cookies * `request.query_params`: Query parameters * `request.path_params`: Path parameters * `request.user`: User data added by authentication middleware * `request.url`: URL information including path, query parameters * `request.meta`: Metadata added by your custom middleware ### Documenting and Validating Query Parameters[¶](#documenting-and-validating-query-parameters "Permanent link") When mounted apps accept [query parameters](https://docs.marimo.io/api/query_params/), it can be helpful to declare, validate, and document them with the help of a [Pydantic model](https://fastapi.tiangolo.com/tutorial/query-param-models/). If a marimo app called `notebooks/items.py` is mounted to `/items`, declaring an endpoint with the same route will take the query parameters through Pydantic model validation first, then redirect to the marimo endpoint. `[](#__codelineno-5-1)# src/main.py [](#__codelineno-5-2)from fastapi import FastAPI, Request, Query [](#__codelineno-5-3)from fastapi.responses import RedirectResponse [](#__codelineno-5-4)from marimo import create_asgi_app [](#__codelineno-5-5)from pathlib import Path [](#__codelineno-5-6)from pydantic import BaseModel, Field [](#__codelineno-5-7)from typing import Annotated, Literal [](#__codelineno-5-8)from urllib.parse import urlencode [](#__codelineno-5-9) [](#__codelineno-5-10)[](#__codelineno-5-11)app = FastAPI() [](#__codelineno-5-12) [](#__codelineno-5-13)[](#__codelineno-5-14)class FilterParams(BaseModel): [](#__codelineno-5-15) limit: int = Field(100, gt=0, le=100) [](#__codelineno-5-16) offset: int = Field(0, ge=0) [](#__codelineno-5-17) order_by: Literal["created_at", "updated_at"] = "created_at" [](#__codelineno-5-18) tags: list[str] = [] [](#__codelineno-5-19) [](#__codelineno-5-20)[](#__codelineno-5-21)@app.get("/items") [](#__codelineno-5-22)async def marimo_items( [](#__codelineno-5-23) request: Request, filter_query: Annotated[FilterParams, Query()] [](#__codelineno-5-24)): [](#__codelineno-5-25) query_params = urlencode(filter_query.model_dump(), doseq=True) [](#__codelineno-5-26) return RedirectResponse(url=f"/items/?{query_params}") [](#__codelineno-5-27) [](#__codelineno-5-28)[](#__codelineno-5-29)server = create_asgi_app(include_code=True, quiet=False) [](#__codelineno-5-30)notebooks_dir = Path(__file__).parent.parent / "notebooks" [](#__codelineno-5-31)[](#__codelineno-5-32)for filename in notebooks_dir.iterdir(): [](#__codelineno-5-33) if filename.suffix == ".py": [](#__codelineno-5-34) app_name = filename.stem [](#__codelineno-5-35) server = server.with_app(path=f"/{app_name}", root=filename) [](#__codelineno-5-36) [](#__codelineno-5-37)[](#__codelineno-5-38)app.mount("/", server.build())` Under the Hood[¶](#under-the-hood "Permanent link") --------------------------------------------------- Behind the scenes, in this mode, marimo is spinning up a new computational kernel in a separate sub-thread (same process) for each new session / app created. There are a few implications of this from a performance and reliability perspective: * If you are running multiple instances of this same server for load balancing, you will need to use sticky sessions in your load balancer to ensure that the same client gets the same kernel each time. * Similarly, attempting to run multiple instances of the same FastAPI process (a common approach with Python web services) on the same node will not work reliably, since only one of them will actually be running the kernel. In summary, there are limitations to how far the approach described here can horizontally scale, so we recommend scaling vertically first. In other words, increase the container CPU/Memory specs before increasing the number of container instances. Authentication - marimo https://docs.marimo.io/guides/deploying/authentication/ marimo provides a simple way to add token/password protection to your marimo server. Given that authentication is a complex topic, marimo does not provide a built-in authentication/authorization system, but instead makes it easy to add your own through ASGI middleware. Enabling Basic Authentication[¶](#enabling-basic-authentication "Permanent link") --------------------------------------------------------------------------------- Authentication is enabled by default when running `marimo edit/tutorial/new`. To disable authentication, you may pass `--no-token` to your `marimo edit/run/new` command from the Terminal. The auth token will be randomly generated when in `Edit mode` and deterministically generated in `Run mode` (based on the code of the notebook). However, you can also pass your own token/password using the `--token-password` flag. `[](#__codelineno-0-1)marimo run my_notebook.py --token --token-password="sup3rs3cr3t"` ### Ways to Authenticate[¶](#ways-to-authenticate "Permanent link") In order to authenticate, you must either pass the token as a password in the `Authorization` header, or as a query parameter under `access_token` in the URL. 1. Enter the token in the login page: If you try to access marimo from a browser, you will be redirected to a login page where you can enter the token. 2. Query parameter: To authenticate using a query parameter, you must pass the token as a query parameter under `access_token` in the URL. For example, to authenticate with the token `sup3rs3cr3t`, you would pass the query parameter `http://localhost:2718?access_token=sup3rs3cr3t`. For convenience, when running locally, marimo will automatically open the URL with the query parameter in your default browser. 3. Basic Authorization header: To authenticate using the `Authorization` header, you must pass the token as a password in the `Authorization` header using the [Basic authentication scheme](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication). For example, to authenticate with the token `sup3rs3cr3t`, you would pass the header `Authorization Basic base64("any_username:sup3rs3cr3t")`. This is not necessary when using a browser, as the marimo server will redirect you to a minimal login page where you can enter the token. Custom Authentication[¶](#custom-authentication "Permanent link") ----------------------------------------------------------------- If you choose to make your marimo application public, you may want to add your own authentication system, along with authorization, rate limiting, etc. You can do this by creating a marimo application programmatically and adding your own middleware to the ASGI application. Here's an example of how you can add authentication to a marimo application using FastAPI: `[](#__codelineno-1-1)from typing import Annotated, Callable, Coroutine [](#__codelineno-1-2)from fastapi.responses import HTMLResponse, RedirectResponse [](#__codelineno-1-3)import marimo [](#__codelineno-1-4)from fastapi import FastAPI, Form, Request, Response [](#__codelineno-1-5)# Custom auth middleware and login page [](#__codelineno-1-6)from my_auth_module import auth_middleware, my_login_route [](#__codelineno-1-7) [](#__codelineno-1-8)[](#__codelineno-1-9)# Create a marimo asgi app [](#__codelineno-1-10)server = ( [](#__codelineno-1-11) marimo.create_asgi_app() [](#__codelineno-1-12) .with_app(path="", root="./pages/index.py") [](#__codelineno-1-13) .with_app(path="/dashboard", root="./pages/dashboard.py") [](#__codelineno-1-14) .with_app(path="/sales", root="./pages/sales.py") [](#__codelineno-1-15)) [](#__codelineno-1-16)[](#__codelineno-1-17)# Create a FastAPI app [](#__codelineno-1-18)app = FastAPI() [](#__codelineno-1-19)[](#__codelineno-1-20)app.add_middleware(auth_middleware) [](#__codelineno-1-21)app.add_route("/login", my_login_route, methods=["POST"]) [](#__codelineno-1-22)[](#__codelineno-1-23)app.mount("/", server.build()) [](#__codelineno-1-24)[](#__codelineno-1-25)# Run the server [](#__codelineno-1-26)if __name__ == "__main__": [](#__codelineno-1-27) import uvicorn [](#__codelineno-1-28) [](#__codelineno-1-29) uvicorn.run(app, host="localhost", port=8000)` For for a full example on implementing OAuth2 with FastAPI, see the [FastAPI OAuth2 example](https://fastapi.tiangolo.com/tutorial/security/oauth2-jwt/). Slurm - marimo https://docs.marimo.io/guides/deploying/deploying_slurm/ Deploy on Slurm/HPC Clusters[¶](#deploy-on-slurmhpc-clusters "Permanent link") ------------------------------------------------------------------------------ This guide shows how to run marimo notebooks on Slurm-managed clusters, including traditional HPC systems and Slurm-on-Kubernetes setups like [SUNK](https://docs.coreweave.com/docs/products/sunk) (CoreWeave). Since marimo notebooks are pure Python scripts, it's easy to submit as Slurm jobs for both interactive development and batch processing. Interactive Development[¶](#interactive-development "Permanent link") --------------------------------------------------------------------- For interactive development, submit a job that runs `marimo edit` and connect via SSH port forwarding. ### Submit the job[¶](#submit-the-job "Permanent link") Create a script (`run_marimo.sh`): `[](#__codelineno-0-1)#!/bin/bash [](#__codelineno-0-2)#SBATCH --job-name=marimo [](#__codelineno-0-3)#SBATCH --output=marimo-%j.out [](#__codelineno-0-4)#SBATCH --cpus-per-task=4 [](#__codelineno-0-5)#SBATCH --mem=16GB [](#__codelineno-0-6)#SBATCH --time=4:00:00 [](#__codelineno-0-7)[](#__codelineno-0-8)# module load or otherwise set up environment [](#__codelineno-0-9)[](#__codelineno-0-10)python -m marimo edit notebook.py --headless --port 3000` Submit it: ### Connect with port forwarding[¶](#connect-with-port-forwarding "Permanent link") Once the job is running, find the compute node and create an SSH tunnel: `[](#__codelineno-2-1)# Find which node your job is running on [](#__codelineno-2-2)squeue -u $USER -o "%.18i %.9P %.8j %.8u %.2t %.10M %.6D %R" [](#__codelineno-2-3)[](#__codelineno-2-4)# Create tunnel (replace NODE with actual node name) [](#__codelineno-2-5)ssh -L 3000:NODE:3000 username@cluster.edu` Open `http://localhost:3000` in your browser. Running as Batch Jobs[¶](#running-as-batch-jobs "Permanent link") ----------------------------------------------------------------- Because marimo notebooks are just Python scripts, they can readily be run as batch jobs. This simple example uses [`mo.cli_args()`](https://docs.marimo.io/api/cli_args/#marimo.cli_args " marimo.cli_args") to pass parameters: `[](#__codelineno-3-1)# /// script [](#__codelineno-3-2)# requires-python = ">=3.12" [](#__codelineno-3-3)# dependencies = [ [](#__codelineno-3-4)# "marimo", [](#__codelineno-3-5)# ] [](#__codelineno-3-6)# /// [](#__codelineno-3-7)[](#__codelineno-3-8)import marimo [](#__codelineno-3-9)[](#__codelineno-3-10)app = marimo.App() [](#__codelineno-3-11) [](#__codelineno-3-12)[](#__codelineno-3-13)@app.cell [](#__codelineno-3-14)def _(): [](#__codelineno-3-15) import marimo as mo [](#__codelineno-3-16) args = mo.cli_args() [](#__codelineno-3-17) print(f"Running with: {args}") [](#__codelineno-3-18) return [](#__codelineno-3-19) [](#__codelineno-3-20)[](#__codelineno-3-21)if __name__ == "__main__": [](#__codelineno-3-22) app.run()` Submit as a job: `[](#__codelineno-4-1)#!/bin/bash [](#__codelineno-4-2)#SBATCH --job-name=marimo-job [](#__codelineno-4-3)#SBATCH --output=marimo-%j.out [](#__codelineno-4-4)#SBATCH --cpus-per-task=4 [](#__codelineno-4-5)#SBATCH --mem=16GB [](#__codelineno-4-6)[](#__codelineno-4-7)python notebook.py --learning-rate 0.01 --epochs 100` ### Using GPUs[¶](#using-gpus "Permanent link") Add GPU resources to your SBATCH directives: Interactive developmentBatch jobs `[](#__codelineno-5-1)#!/bin/bash [](#__codelineno-5-2)#SBATCH --job-name=marimo [](#__codelineno-5-3)#SBATCH --output=marimo-%j.out [](#__codelineno-5-4)#SBATCH --partition=gpu [](#__codelineno-5-5)#SBATCH --gres=gpu:1 [](#__codelineno-5-6)#SBATCH --cpus-per-task=4 [](#__codelineno-5-7)#SBATCH --mem=16GB [](#__codelineno-5-8)#SBATCH --time=4:00:00 [](#__codelineno-5-9)[](#__codelineno-5-10)# module load or otherwise set up environment [](#__codelineno-5-11)[](#__codelineno-5-12)python -m marimo edit notebook.py --headless --port 3000` `[](#__codelineno-6-1)#!/bin/bash [](#__codelineno-6-2)#SBATCH --job-name=marimo-gpu [](#__codelineno-6-3)#SBATCH --partition=gpu [](#__codelineno-6-4)#SBATCH --gres=gpu:1 [](#__codelineno-6-5)#SBATCH --cpus-per-task=8 [](#__codelineno-6-6)#SBATCH --mem=32GB [](#__codelineno-6-7)[](#__codelineno-6-8)python notebook.py` Inlining configuration in notebook files[¶](#inlining-configuration-in-notebook-files "Permanent link") ------------------------------------------------------------------------------------------------------- You can inline SBATCH directives in your notebook file. If used alongside marimo's support for [inlining package dependencies](https://docs.marimo.io/guides/package_management/inlining_dependencies/) ("sandboxing"), this lets you create fully self-contained notebooks. Interactive development `[](#__codelineno-7-1)#!/usr/bin/env -S python -m marimo edit --sandbox [](#__codelineno-7-2)#SBATCH --job-name=marimo-job [](#__codelineno-7-3)#SBATCH --output=marimo-%j.out [](#__codelineno-7-4)#SBATCH --cpus-per-task=4 [](#__codelineno-7-5)#SBATCH --mem=16GB [](#__codelineno-7-6)[](#__codelineno-7-7)# /// script [](#__codelineno-7-8)# requires-python = ">=3.12" [](#__codelineno-7-9)# dependencies = [ [](#__codelineno-7-10)# "marimo", [](#__codelineno-7-11)# ] [](#__codelineno-7-12)# /// [](#__codelineno-7-13)[](#__codelineno-7-14)import marimo [](#__codelineno-7-15)[](#__codelineno-7-16)app = marimo.App() [](#__codelineno-7-17) [](#__codelineno-7-18)[](#__codelineno-7-19)@app.cell [](#__codelineno-7-20)def _(): [](#__codelineno-7-21) import marimo as mo [](#__codelineno-7-22) print("Hello World!") [](#__codelineno-7-23) return [](#__codelineno-7-24) [](#__codelineno-7-25)[](#__codelineno-7-26)if __name__ == "__main__": [](#__codelineno-7-27) app.run()` Batch job `[](#__codelineno-8-1)#!/usr/bin/env -S python [](#__codelineno-8-2)#SBATCH --job-name=marimo-job [](#__codelineno-8-3)#SBATCH --output=marimo-%j.out [](#__codelineno-8-4)#SBATCH --cpus-per-task=4 [](#__codelineno-8-5)#SBATCH --mem=16GB [](#__codelineno-8-6)[](#__codelineno-8-7)# /// script [](#__codelineno-8-8)# requires-python = ">=3.12" [](#__codelineno-8-9)# dependencies = [ [](#__codelineno-8-10)# "marimo", [](#__codelineno-8-11)# ] [](#__codelineno-8-12)# /// [](#__codelineno-8-13)[](#__codelineno-8-14)import marimo [](#__codelineno-8-15)[](#__codelineno-8-16)app = marimo.App() [](#__codelineno-8-17) [](#__codelineno-8-18)[](#__codelineno-8-19)@app.cell [](#__codelineno-8-20)def _(): [](#__codelineno-8-21) import marimo as mo [](#__codelineno-8-22) print("Hello World!") [](#__codelineno-8-23) return [](#__codelineno-8-24) [](#__codelineno-8-25)[](#__codelineno-8-26)if __name__ == "__main__": [](#__codelineno-8-27) app.run()` Make executable and submit directly: `[](#__codelineno-9-1)chmod +x notebook.py [](#__codelineno-9-2)sbatch notebook.py` Sandboxing requires [uv](https://docs.astral.sh/uv/getting-started/installation/) to be installed. Learn more[¶](#learn-more "Permanent link") ------------------------------------------- * [Slurm examples](https://github.com/marimo-team/marimo/tree/main/examples/slurm) - Complete working examples * [Slurm documentation](https://slurm.schedmd.com/documentation.html) * [SUNK (Slurm on Kubernetes)](https://docs.coreweave.com/docs/products/sunk) * [marimo CLI arguments](https://docs.marimo.io/api/cli_args/) Docker - marimo https://docs.marimo.io/guides/deploying/deploying_docker/ Deploy with Docker[¶](#deploy-with-docker "Permanent link") ----------------------------------------------------------- Prerequisites[¶](#prerequisites "Permanent link") ------------------------------------------------- * A marimo notebook or app: `app.py` that you want to deploy * A `requirements.txt` file that contains the dependencies needed for your application to run Create a Dockerfile[¶](#create-a-dockerfile "Permanent link") ------------------------------------------------------------- `Dockerfile` is a text file that contains instructions for building a Docker image. Here's an example `Dockerfile` for a marimo notebook: `[](#__codelineno-0-1)# syntax=docker/dockerfile:1.4 [](#__codelineno-0-2)[](#__codelineno-0-3)# Choose a python version that you know works with your application [](#__codelineno-0-4)FROM python:3.11-slim [](#__codelineno-0-5)[](#__codelineno-0-6)# Install uv for fast package management [](#__codelineno-0-7)COPY --from=ghcr.io/astral-sh/uv:0.4.20 /uv /bin/uv [](#__codelineno-0-8)ENV UV_SYSTEM_PYTHON=1 [](#__codelineno-0-9)[](#__codelineno-0-10)WORKDIR /app [](#__codelineno-0-11)[](#__codelineno-0-12)# Copy requirements file [](#__codelineno-0-13)COPY --link requirements.txt . [](#__codelineno-0-14)[](#__codelineno-0-15)# Install the requirements using uv [](#__codelineno-0-16)RUN uv pip install -r requirements.txt [](#__codelineno-0-17)[](#__codelineno-0-18)# Copy application files [](#__codelineno-0-19)COPY --link app.py . [](#__codelineno-0-20)# Uncomment the following line if you need to copy additional files [](#__codelineno-0-21)# COPY --link . . [](#__codelineno-0-22)[](#__codelineno-0-23)EXPOSE 8080 [](#__codelineno-0-24)[](#__codelineno-0-25)# Create a non-root user and switch to it [](#__codelineno-0-26)RUN useradd -m app_user [](#__codelineno-0-27)USER app_user [](#__codelineno-0-28)[](#__codelineno-0-29)CMD [ "marimo", "run", "app.py", "--host", "0.0.0.0", "-p", "8080" ]` Breaking it down[¶](#breaking-it-down "Permanent link") ------------------------------------------------------- `FROM` instructs what base image to choose. In our case, we chose Python 3.11 with the “slim” variant. This removes a lot of extra dependencies. You can always add them back as needed. A slimmer Dockerfile (by bytes) means quick to build, deploy, and start up. The `WORKDIR` sets the current working directory. In most cases, this does not need to be changed. The `COPY` steps will copy all the necessary files into your docker. By adding `--link`, we end up creating a new layer that does not get invalidated by previous changes. This can be especially important for expensive install steps that do not depend on each other. `RUN` lets us run shell commands. We can use this to install dependencies via apt-get, pip, or package managers. In our case, we use it to install our requirements.txt with pip. Our `EXPOSE` step tells us which port is exposed to be accessed from outside the Docker container. This will need to match the port at which we run our marimo application on. We then create a new user and switch to it with the `USER` instruction, in order to limit the permissions of the marimo application. This is not required, but recommended. The final step `CMD` instructions what command to run when we run our docker container. Here we run our marimo application at the port 8080. Running your application locally[¶](#running-your-application-locally "Permanent link") --------------------------------------------------------------------------------------- Once you have your Dockerfile and your application files, you can test it out locally: `[](#__codelineno-1-1)# Build your image, and tag it as my_app [](#__codelineno-1-2)docker build -t my_app . [](#__codelineno-1-3)[](#__codelineno-1-4)# Start your container, mapping port 8080 [](#__codelineno-1-5)docker run -p 8080:8080 -it my_app [](#__codelineno-1-6)[](#__codelineno-1-7)# Visit http://localhost:8080` After verifying that your application runs without errors, you can use these files to deploy your application on your preferred cloud provider that supports dockerized applications. Health checks[¶](#health-checks "Permanent link") ------------------------------------------------- You can add a health check to your Dockerfile to ensure that your application is running as expected. This is especially useful when deploying to a cloud provider. `[](#__codelineno-2-1)HEALTHCHECK --interval=30s --timeout=3s \ [](#__codelineno-2-2) CMD curl -f http://localhost:8080/health || exit 1` The following endpoints may be useful when deploying your application: * `/health` or `/healthz` - A health check endpoint that returns a 200 status code if the application is running as expected * `/api/status` - A status endpoint that returns a JSON object with the status of the server HuggingFace - marimo https://docs.marimo.io/guides/deploying/deploying_hugging_face/ Deploy to Hugging Face[¶](#deploy-to-hugging-face "Permanent link") ------------------------------------------------------------------- Hugging Face is a platform that allows you to deploy machine learning models and applications easily. You can deploy a marimo notebook as an interactive web app on Hugging Face Spaces with just a few steps. Deploy[¶](#deploy "Permanent link") ----------------------------------- To deploy your marimo notebook to Hugging Face Spaces: 1. Create a new Space on Hugging Face by forking or copying the following template: [https://huggingface.co/spaces/marimo-team/marimo-app-template/tree/main](https://huggingface.co/spaces/marimo-team/marimo-app-template/tree/main) 2. Replace the contents of the `app.py` file with your marimo notebook. 3. Update the `requirements.txt` file to include any other dependencies your notebook requires. 4. Commit these files to your Space, and Hugging Face will automatically deploy your marimo notebook as an interactive web app. For more detailed instructions and advanced configurations, please refer to the [Hugging Face Spaces documentation](https://huggingface.co/docs/hub/spaces-overview). Railway - marimo https://docs.marimo.io/guides/deploying/deploying_railway/ Deploy to Railway[¶](#deploy-to-railway "Permanent link") --------------------------------------------------------- Railway is a platform that allows you to deploy Dockerize containers easily. Using this pre-built template, Railway will deploy a single-instance marimo edit server with persistent storage in a few clicks. Deploy[¶](#deploy "Permanent link") ----------------------------------- nginx - marimo https://docs.marimo.io/guides/deploying/deploying_nginx/ Deploy with nginx[¶](#deploy-with-nginx "Permanent link") --------------------------------------------------------- nginx is a popular web server that can be used as a reverse proxy for web applications. This guide will show you how to deploy marimo behind an nginx reverse proxy. Prerequisites[¶](#prerequisites "Permanent link") ------------------------------------------------- * A marimo notebook or app that you want to deploy * nginx installed on your server * Basic understanding of nginx configuration Configuration[¶](#configuration "Permanent link") ------------------------------------------------- Create a new configuration file in `/etc/nginx/conf.d/` (e.g., `marimo.conf`): `[](#__codelineno-0-1)server { [](#__codelineno-0-2) server_name your-domain.com; [](#__codelineno-0-3) [](#__codelineno-0-4) location / { [](#__codelineno-0-5) proxy_set_header Host $host; [](#__codelineno-0-6) proxy_set_header X-Real-IP $remote_addr; [](#__codelineno-0-7) proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; [](#__codelineno-0-8) proxy_set_header X-Forwarded-Proto $scheme; [](#__codelineno-0-9) proxy_pass http://127.0.0.1:2718; [](#__codelineno-0-10) [](#__codelineno-0-11) # Required for WebSocket support [](#__codelineno-0-12) proxy_http_version 1.1; [](#__codelineno-0-13) proxy_set_header Upgrade $http_upgrade; [](#__codelineno-0-14) proxy_set_header Connection "upgrade"; [](#__codelineno-0-15) proxy_read_timeout 600; [](#__codelineno-0-16) } [](#__codelineno-0-17) [](#__codelineno-0-18) # Optional: Serve static files [](#__codelineno-0-19) location /static/ { [](#__codelineno-0-20) alias /path/to/your/static/files/; [](#__codelineno-0-21) } [](#__codelineno-0-22)}` Breaking it down[¶](#breaking-it-down "Permanent link") ------------------------------------------------------- * `server_name`: Replace with your domain name * `proxy_pass`: Points to your marimo application (default port is 2718) * WebSocket support: The following lines are required for marimo to function properly: `[](#__codelineno-1-1)proxy_http_version 1.1; [](#__codelineno-1-2)proxy_set_header Upgrade $http_upgrade; [](#__codelineno-1-3)proxy_set_header Connection "upgrade";` * `proxy_read_timeout`: Increased to 600 seconds to handle long-running operations Running your application[¶](#running-your-application "Permanent link") ----------------------------------------------------------------------- 1. Start your marimo application: `[](#__codelineno-2-1)marimo run app.py --host 127.0.0.1 --port 2718` 2. Test your nginx configuration: 3. Reload nginx to apply changes: Your marimo application should now be accessible at your domain. SSL/HTTPS[¶](#sslhttps "Permanent link") ---------------------------------------- For production deployments, it's recommended to use HTTPS. You can use [Certbot](https://certbot.eff.org/) to automatically configure SSL with Let's Encrypt certificates. Common Issues[¶](#common-issues "Permanent link") ------------------------------------------------- ### Kernel Not Found[¶](#kernel-not-found "Permanent link") If you see a "kernel not found" error, ensure that: 1. WebSocket support is properly configured in your nginx configuration 2. The proxy headers are correctly set 3. Your marimo application is running and accessible at the specified proxy\_pass address Configuration - marimo https://docs.marimo.io/guides/configuration/ marimo offers two types of configuration: User Configuration and App Configuration. Both can be easily managed through the Settings menu in the marimo editor. App Configuration[¶](#app-configuration "Permanent link") --------------------------------------------------------- App Configuration is specific to each notebook and is stored in the `notebook.py` file. This allows you to customize various aspects of your notebook, including: * Notebook width * Notebook title * [Custom CSS](https://docs.marimo.io/guides/configuration/theming/) * [Custom HTML Head](https://docs.marimo.io/guides/configuration/html_head/) * Automatically download HTML snapshots Configure these settings through the notebook menu (⚙️) in the top-right corner. User Configuration[¶](#user-configuration "Permanent link") ----------------------------------------------------------- User Configuration applies globally across all marimo notebooks and is stored in a `$XDG_CONFIG_HOME/marimo/marimo.toml` file. While you can edit the `$XDG_CONFIG_HOME/marimo/marimo.toml` file directly, we recommend using the marimo UI for a more user-friendly experience. You can customize the following settings: * [Runtime](https://docs.marimo.io/guides/configuration/runtime_configuration/), including whether notebooks autorun * [Hotkeys](https://docs.marimo.io/guides/editor_features/hotkeys/) * Completion (auto-completion, AI copilot, etc.) * Display (theme, font size, output placement, etc.) * Autosave * [Package management](https://docs.marimo.io/guides/editor_features/package_management/#package-management) * Server settings * [VIM keybindings](https://docs.marimo.io/guides/editor_features/overview/#vim-keybindings) * Formatting settings * [AI assistance](https://docs.marimo.io/guides/editor_features/ai_completion/) * [Snippets](https://docs.marimo.io/guides/configuration/snippets/) * Experimental features ### User configuration file[¶](#user-configuration-file "Permanent link") marimo searches for the `.marimo.toml` file in the following order: 1. Current directory 2. Parent directories (moving up the tree) 3. Home directory (`~/.marimo.toml`) 4. [XDG](https://xdgbasedirectoryspecification.com/) directory (`~/.config/marimo/marimo.toml` or `$XDG_CONFIG_HOME/marimo/marimo.toml`) If no `.marimo.toml` file is found, marimo creates one for you in an XDG config compliant way. To view your current configuration and locate the config file, run: To describe the user configuration options, run: ### Overriding settings with pyproject.toml[¶](#overriding-settings-with-pyprojecttoml "Permanent link") You can override user configuration settings with a `pyproject.toml` file. This is useful for sharing configurations across teams or ensuring consistency across notebooks. You must edit the `pyproject.toml` file directly to override settings. For example, the following `pyproject.toml` file overrides the `autosave` setting in the user configuration: pyproject.toml `[](#__codelineno-2-1)[tool.marimo.formatting] [](#__codelineno-2-2)line_length = 120 [](#__codelineno-2-3)[](#__codelineno-2-4)[tool.marimo.display] [](#__codelineno-2-5)default_width = "full" [](#__codelineno-2-6)[](#__codelineno-2-7)[tool.marimo.runtime] [](#__codelineno-2-8)default_sql_output = "native"` You can override any user configuration setting in this way. To find these settings run `marimo config show`. Overridden settings Settings overridden in `pyproject.toml` or script metadata cannot be changed through the marimo editor's settings menu. Any changes made to overridden settings in the editor will not take effect. ### Script Metadata Configuration[¶](#script-metadata-configuration "Permanent link") You can also configure marimo settings directly in your notebook files using script metadata (PEP 723). Add a `script` block at the top of your notebook: `[](#__codelineno-3-1)# /// script [](#__codelineno-3-2)# [tool.marimo.runtime] [](#__codelineno-3-3)# auto_instantiate = false [](#__codelineno-3-4)# on_cell_change = "lazy" [](#__codelineno-3-5)# [tool.marimo.display] [](#__codelineno-3-6)# theme = "dark" [](#__codelineno-3-7)# cell_output = "below" [](#__codelineno-3-8)# ///` Configuration precedence Script metadata configuration has the highest precedence, followed by `pyproject.toml` configuration, then user configuration: **Script config > pyproject.toml config > user config** Environment Variables[¶](#environment-variables "Permanent link") ----------------------------------------------------------------- marimo supports the following environment variables for advanced configuration: | Environment Variable | Description | Default Value | | --- | --- | --- | | `MARIMO_OUTPUT_MAX_BYTES` (deprecated, use `pyproject.toml`) | Maximum size of output that marimo will display. Outputs larger than this will be truncated. | 8,000,000 (8MB) | | `MARIMO_STD_STREAM_MAX_BYTES` (deprecated, use `pyproject.toml`) | Maximum size of standard stream (stdout/stderr) output that marimo will display. Outputs larger than this will be truncated. | 1,000,000 (1MB) | | `MARIMO_SKIP_UPDATE_CHECK` | If set to "1", marimo will skip checking for updates when starting. | Not set | | `MARIMO_SQL_DEFAULT_LIMIT` | Default limit for SQL query results. If not set, no limit is applied. | Not set | ### Tips[¶](#tips "Permanent link") * The `.marimo.toml` file can be version controlled to share configurations across teams * App configurations can be committed with notebooks to ensure consistent appearance Runtime configuration - marimo https://docs.marimo.io/guides/configuration/runtime_configuration/ Through the notebook settings menu or notebook footer, you can configure how and when marimo runs cells. On startup[¶](#on-startup "Permanent link") ------------------------------------------- Toggle this setting to control whether marimo notebooks opened with `marimo edit` automatically run on startup _When sharing a notebook as an app with `marimo run`, this setting has no effect._ On cell change: disabling autorun on cell change (lazy execution)[¶](#on-cell-change-disabling-autorun-on-cell-change-lazy-execution "Permanent link") ------------------------------------------------------------------------------------------------------------------------------------------------------ By default, when a cell is run or a UI element is interacted with, marimo automatically runs cells that reference any of its variables. **You can disable automatic execution of cell's descendants in the notebook settings menu by setting `"On cell change"` to `"lazy"`.** When the runtime is lazy, running a cell marks affected cells as stale but doesn't automatically run them. Lazy evaluation means cells are only run when their outputs are needed. If you run a cell that has stale ancestors, those ancestors will also run to make sure your cell doesn't use stale inputs. You can always click the notebook run button or use the keyboard shortcut to run all stale cells. **When should I use lazy evaluation?** Choosing the lazy runtime can be helpful when working on notebooks with expensive cells. Tip: speed up expensive notebooks with marimo's smart caching In addition to runtime configuration, marimo also provides [opt-in caching](https://docs.marimo.io/api/caching/) to help you work with expensive or side-effectful notebooks. marimo's can cache expensive functions in memory and expensive blocks of code to disk, letting you skip entire sections of your code and automatically loading variables in memory on notebook startup. Read our [caching guide](https://docs.marimo.io/api/caching/) to learn more. _When sharing a notebook as an app with `marimo run`, this setting has no effect._ On module change[¶](#on-module-change "Permanent link") ------------------------------------------------------- When module autoreloading is enabled, marimo automatically runs cells when you edit Python files. Based on static analysis, the reloader only runs cells affected by your edits. The reloader is recursive, meaning that marimo tracks modifications for modules imported by your notebook's imported modules too. Why autoreload? Autoreloading enables a workflow that many developers find productive: develop complex logic in Python modules, and use the marimo notebook as a DAG or main script that orchestrates your logic. Autoreloading comes in two types: 1. **autorun**: automatically re-runs cells affected by module modification. When set to autorun, marimo's reloader automatically run cells when you edit Python files. 2. **lazy**: marks cells affected by module modifications as stale, letting you know which cells need to be re-run. When set to lazy, marimo's reloader marks cells as stale when you edit Python files. Python path[¶](#python-path "Permanent link") --------------------------------------------- By default, marimo will not add any additional directories to the Python path. This keeps the behavior of `marimo edit nb.py` and `python nb.py` consistent. You can add directories to the Python path by setting the `pythonpath` key in the runtime configuration. These directories will be added to the head of `sys.path`, similar to how the `PYTHONPATH` environment variable works. This allows Python to find and import modules from these directories. pyproject.toml `[](#__codelineno-0-1)[tool.marimo.runtime] [](#__codelineno-0-2)pythonpath = ["project/src"]` Consider alternatives to path manipulation When possible, it's preferred to avoid path manipulation. If you want to work on a module in a separate directory alongside your notebooks, we recommend creating a _package_ and including marimo as a project dependency. `[](#__codelineno-1-1)uv init --lib my_package [](#__codelineno-1-2)cd my_package [](#__codelineno-1-3)uv add --dev marimo [](#__codelineno-1-4)uv run marimo edit notebook.py # my_package is available in notebook environment` This will make it easier to share your library code. For multiple packages, consider configuring [uv workspaces](https://docs.astral.sh/uv/concepts/projects/workspaces/). See our guide on [notebooks in existing projects](https://docs.marimo.io/guides/package_management/notebooks_in_projects/) for more details. Environment variables[¶](#environment-variables "Permanent link") ----------------------------------------------------------------- ### .env files[¶](#env-files "Permanent link") marimo supports loading environment variables from `.env` files. This is useful for managing configuration that should not be committed to version control, such as API keys or database credentials. The `.env` next to your `pyproject.toml` is loaded by default. To configure multiple or a different location, you can specify them in your configuration: pyproject.toml `[](#__codelineno-2-1)[tool.marimo.runtime] [](#__codelineno-2-2)dotenv = [".env", ".env.testing"]` Environment variables from your `dotenv` will be surfaced in the UI when creating databases. WebAssembly notebooks - marimo https://docs.marimo.io/guides/wasm/ marimo lets you execute notebooks _entirely in the browser_, without a backend executing Python. marimo notebooks that run entirely in the browser are called WebAssembly notebooks, or WASM notebooks for short. Check for WebAssembly compatibility Not all notebooks are compatible with WebAssembly. If you use coding agents like Claude Code, you can use our [official skills](https://docs.marimo.io/guides/generate_with_ai/skills/) to automatically check for WebAssembly compatibility of your notebooks. Sharing interactive previews of GitHub notebooks Read the [molab docs](https://docs.marimo.io/guides/molab/) to learn how to share WebAssembly previews of notebooks hosted on GitHub, and how to embed WebAssembly notebooks in other webpages such as documentation. WASM notebooks have three benefits compared to notebooks hosted using a traditional client-server model. WASM notebooks: 1. eliminate the need to install Python, making scientific computing accessible; 2. eliminate the cost and complexity of deploying backend infrastructure, making it easy to share notebooks; 3. eliminate network requests to a remote Python runner, making development feel snappy. When should I use WASM notebooks? WASM notebooks are excellent for sharing your work, quickly experimenting with code and models, doing lightweight data exploration, authoring blog posts, tutorials, and educational materials, and even building tools. For notebooks that do heavy computation, [use marimo](https://docs.marimo.io/getting_started/) on your own machine/server or on [molab](https://molab.marimo.io/notebooks). **Try it!** Try editing the below notebook (your browser, not a backend server, is executing it!) _This feature is powered by [Pyodide](https://pyodide.org/), a port of Python to WebAssembly that enables browsers to run Python code._ Creating WASM notebooks[¶](#creating-wasm-notebooks "Permanent link") --------------------------------------------------------------------- marimo provides three ways to create and share WASM notebooks: 1. [molab](https://docs.marimo.io/guides/molab/). Our free cloud-hosted marimo notebook service. Append `/wasm` to [GitHub previews](https://docs.marimo.io/guides/molab/#preview-notebooks-from-github) to create interactive previews of notebooks hosted on GitHub. molab also allows embedding WebAssembly notebooks in other [webpages](https://docs.marimo.io/guides/publishing/embedding/) (we do this throughout these docs). 2. [Export to WASM HTML](https://docs.marimo.io/guides/exporting/webassembly_html/), which you can host on GitHub Pages or self-host. You can also use [a GitHub action](https://docs.marimo.io/guides/publishing/github/#publish-using-github-actions). 3. Try our ephemeral [WebAssembly playground](https://marimo.app/); unlike molab, notebooks created at the playground are not saved. Packages[¶](#packages "Permanent link") --------------------------------------- Use `--sandbox` for seamless package installation If you're developing notebooks locally that you plan to share as WASM notebooks, create them with `marimo edit --sandbox notebook.py`. This inlines your package dependencies into the notebook file, ensuring they are seamlessly installed in our WebAssembly environment. See [package management](https://docs.marimo.io/guides/editor_features/package_management/) for more details. Rendering performance To make sure markdown and other elements render quickly: make sure to put `import marimo as mo` in its own cell, with no other lines of code. WASM notebooks come with many packages pre-installed, including NumPy, SciPy, scikit-learn, pandas, and matplotlib; see [Pyodide's documentation](https://pyodide.org/en/stable/usage/packages-in-pyodide.html) for a full list. If you attempt to import a package that is not installed, marimo will attempt to automatically install it for you. To manually install packages, use [`micropip`](https://micropip.pyodide.org/en/stable/project/usage.html): In one cell, import micropip: In the next cell, install packages: `[](#__codelineno-2-1)await micropip.install("plotly") [](#__codelineno-2-2)import plotly` ### Supported packages[¶](#supported-packages "Permanent link") All packages with pure Python wheels on PyPI are supported, as well as additional packages like NumPy, SciPy, scikit-learn, duckdb, polars, and more. For a full list of supported packages, see [Pyodide's documentation on supported packages.](https://pyodide.org/en/stable/usage/packages-in-pyodide.html) If you want a package to be supported, consider [filing an issue](https://github.com/pyodide/pyodide/issues/new?assignees=&labels=new+package+request&projects=&template=package_request.md&title=). Including data[¶](#including-data "Permanent link") --------------------------------------------------- **For notebooks exported to WASM HTML.** To include data files in notebooks [exported to WASM HTML](https://docs.marimo.io/guides/exporting/webassembly_html/), place them in a `public/` folder in the same directory as your notebook. When you export to WASM HTML, the public folder will be copied to the export directory. In order to access data both locally and when an exported notebook runs via WebAssembly (e.g., hosted on GitHub Pages), use [`mo.notebook_location()`](https://docs.marimo.io/api/miscellaneous/#marimo.notebook_location " marimo.notebook_location") to construct the path to your data: `[](#__codelineno-3-1)import polars as pl [](#__codelineno-3-2)[](#__codelineno-3-3)path_to_csv = mo.notebook_location() / "public" / "data.csv" [](#__codelineno-3-4)df = pl.read_csv(str(path_to_csv)) [](#__codelineno-3-5)df.head()` **Fetching data files from the web.** Instead of bundling data files with your notebook, you can host data files on the web and fetch them in your notebook. Depending on where your files are hosted, you may need to use a CORS Proxy; see the [Pyodide documentation](https://pyodide.org/en/stable/usage/loading-packages.html#installing-wheels-from-arbitrary-urls) for more details. **molab notebooks.** When opening a notebook from GitHub on [molab](https://docs.marimo.io/guides/molab/), all the files in the GitHub repo are made available to your notebook. Detecting WebAssembly[¶](#detecting-webassembly "Permanent link") ----------------------------------------------------------------- To check if your notebook is running in a WebAssembly environment, use: `[](#__codelineno-4-1)import sys [](#__codelineno-4-2)[](#__codelineno-4-3)if "pyodide" in sys.modules: [](#__codelineno-4-4) # Running in WebAssembly [](#__codelineno-4-5) ... [](#__codelineno-4-6)else: [](#__codelineno-4-7) # Running locally [](#__codelineno-4-8) ...` This is useful for branching logic, such as using `micropip` for package installation in WASM while using standard imports locally. Limitations[¶](#limitations "Permanent link") --------------------------------------------- While WASM notebooks let you share marimo notebooks seamlessly, they have some limitations. **Packages.** Many but not all packages are supported. All packages with pure Python wheels on PyPI are supported, as well as additional packages like NumPy, SciPy, scikit-learn, duckdb, polars, and more. For a full list of supported packages, see [Pyodide's documentation on supported packages.](https://pyodide.org/en/stable/usage/packages-in-pyodide.html) If you want a package to be supported, consider [filing an issue](https://github.com/pyodide/pyodide/issues/new?assignees=&labels=new+package+request&projects=&template=package_request.md&title=). **PDB.** PDB is not currently supported. **Threading and multi-processing.** WASM notebooks do not support multithreading and multiprocessing. [This may be fixed in the future](https://github.com/pyodide/pyodide/issues/237). **Memory.** WASM notebooks have a memory limit of 2GB; this may be increased in the future. If memory consumption is an issue, try offloading memory-intensive computations to hosted APIs or precomputing expensive operations. Browser support[¶](#browser-support "Permanent link") ----------------------------------------------------- WASM notebooks are supported in the latest versions of Chrome, Firefox, Edge, and Safari. Chrome is the recommended browser for WASM notebooks as it seems to have the best performance and compatibility. LLM Providers - marimo https://docs.marimo.io/guides/configuration/llm_providers/ Configuring LLM providers[¶](#configuring-llm-providers "Permanent link") ------------------------------------------------------------------------- Connect marimo to an LLM via the notebook Settings panel (recommended) or by editing `marimo.toml` directly. **Prefer going through the notebook settings menu to avoid errors with the config file.** To locate your config file: The path to `marimo.toml` is printed at the top of the output. Model configuration[¶](#model-configuration "Permanent link") ------------------------------------------------------------- ### Model roles and routing[¶](#model-roles-and-routing "Permanent link") marimo uses three roles: * **`chat_model`**: chat panel * **`edit_model`**: refactor cells (Cmd/Ctrl-Shift-E) and Generate with AI * **`autocomplete_model`**: inline code completion Models are written as `provider/model`, and the provider prefix routes to the matching config section: marimo.toml `[](#__codelineno-1-1)[ai.models] [](#__codelineno-1-2)chat_model = "openai/gpt-4o-mini" # Routes to OpenAI config [](#__codelineno-1-3)edit_model = "anthropic/claude-3-sonnet" # Routes to Anthropic config [](#__codelineno-1-4)autocomplete_model = "ollama/codellama" # Routes to Ollama config [](#__codelineno-1-5)autocomplete_model = "some_other_provider/some_model" # Routes to OpenAI compatible config` ### Custom models[¶](#custom-models "Permanent link") Add custom entries to the model dropdown: marimo.toml `[](#__codelineno-2-1)[ai.models] [](#__codelineno-2-2)custom_models = ["ollama/somemodel"]` Rules and Max tokens[¶](#rules-and-max-tokens "Permanent link") --------------------------------------------------------------- Add custom rules or set the maximum number of tokens that the AI model can use. marimo.toml `[](#__codelineno-3-1)[ai] [](#__codelineno-3-2)rules = """ [](#__codelineno-3-3)- Always use type hints; prefer polars over pandas [](#__codelineno-3-4)""" [](#__codelineno-3-5)max_tokens = 1000` Supported providers[¶](#supported-providers "Permanent link") ------------------------------------------------------------- Configure LLM providers in the notebook settings panel. You can configure the following providers: * Anthropic * AWS Bedrock * GitHub * Google AI * DeepSeek * xAI * LM Studio * Mistral * Ollama * OpenAI * OpenRouter * Weights & Biases * Together AI * Vercel v0 * and any OpenAI-compatible provider Below we describe how to connect marimo to your AI provider. ### OpenAI[¶](#openai "Permanent link") **Requirements** * `pip install openai` or `uv add openai` **Configuration** marimo.toml `[](#__codelineno-4-1)[ai.models] [](#__codelineno-4-2)chat_model = "openai/gpt-4o-mini" [](#__codelineno-4-3)edit_model = "openai/gpt-4o" [](#__codelineno-4-4)# See https://platform.openai.com/docs/models for the latest list [](#__codelineno-4-5)[](#__codelineno-4-6)[ai.open_ai] [](#__codelineno-4-7)# Get an API key at https://platform.openai.com/account/api-keys [](#__codelineno-4-8)api_key = "sk-proj-..."` OpenAI-compatible providers If your model does not start with `openai/`, it will not be routed to the OpenAI config, and likely will be routed to the OpenAI-compatible config. Reasoning models (o1, o3, etc.) These models can incur higher costs due to separate reasoning tokens. Prefer smaller responses for refactors or autocompletion, and review your provider limits. ### Anthropic[¶](#anthropic "Permanent link") **Requirements** * Create an account and key: [Anthropic Console](https://console.anthropic.com/settings/keys) **Configuration** marimo.toml `[](#__codelineno-5-1)[ai.models] [](#__codelineno-5-2)chat_model = "anthropic/claude-3-7-sonnet-latest" # other options: claude-3-haiku, claude-3-opus [](#__codelineno-5-3)# See Anthropic model list: https://docs.anthropic.com/en/docs/about-claude/models [](#__codelineno-5-4)[](#__codelineno-5-5)[ai.anthropic] [](#__codelineno-5-6)api_key = "sk-ant-..."` ### AWS Bedrock[¶](#aws-bedrock "Permanent link") AWS Bedrock exposes multiple foundation models via a unified AWS API. **Requirements** * `pip install boto3` * Enable model access in the Bedrock console * AWS credentials via `aws configure`, env vars, or `~/.aws/credentials` **Configuration** marimo.toml `[](#__codelineno-6-1)[ai.models] [](#__codelineno-6-2)chat_model = "bedrock/anthropic.claude-3-sonnet-latest" [](#__codelineno-6-3)# Example model families include Anthropic Claude, Meta Llama, Cohere Command [](#__codelineno-6-4)[](#__codelineno-6-5)[ai.bedrock] [](#__codelineno-6-6)region_name = "us-east-1" # AWS region where Bedrock is available [](#__codelineno-6-7)# Optional AWS profile name (from ~/.aws/credentials) [](#__codelineno-6-8)profile_name = "my-profile"` Use `profile_name` for a non-default named profile, or rely on env vars/standard AWS resolution. For regional inference models, specify the inference profile ID (e.g., `bedrock/eu.anthropic.claude-sonnet-4-20250514-v1:0`) and corresponding region. Required AWS Bedrock permissions Ensure your IAM policy allows `bedrock:InvokeModel` and `bedrock:InvokeModelWithResponseStream` for the models you plan to use. ### Google AI[¶](#google-ai "Permanent link") **Requirements** * `pip install google-genai` You can use Google AI via two backends: **Google AI Studio** (API key) or **Google Vertex AI** (no API key required). #### Using Google AI Studio (API key)[¶](#using-google-ai-studio-api-key "Permanent link") 1. Sign up at [Google AI Studio](https://aistudio.google.com/app/apikey) and obtain your API key. 2. Configure `marimo.toml` (or set these in the editor Settings): marimo.toml `[](#__codelineno-7-1)[ai.models] [](#__codelineno-7-2)chat_model = "google/gemini-2.5-pro" [](#__codelineno-7-3)# or any model from https://ai.google.dev/gemini-api/docs/models/gemini [](#__codelineno-7-4)[](#__codelineno-7-5)[ai.google] [](#__codelineno-7-6)api_key = "AI..."` #### Using Google Vertex AI (no API key required)[¶](#using-google-vertex-ai-no-api-key-required "Permanent link") 1. Ensure you have access to a Google Cloud project with Vertex AI enabled. 2. Set the following environment variables before starting marimo: `[](#__codelineno-8-1)export GOOGLE_GENAI_USE_VERTEXAI=true [](#__codelineno-8-2)export GOOGLE_CLOUD_PROJECT='your-project-id' [](#__codelineno-8-3)export GOOGLE_CLOUD_LOCATION='us-central1'` * `GOOGLE_GENAI_USE_VERTEXAI=true` tells the client to use Vertex AI. * `GOOGLE_CLOUD_PROJECT` is your GCP project ID. * `GOOGLE_CLOUD_LOCATION` is your region (e.g., `us-central1`). 3. No API key is needed in your `marimo.toml` for Vertex AI. For details and advanced configuration, see the `google-genai` Python client docs: `https://googleapis.github.io/python-genai/#create-a-client`. ### Azure[¶](#azure "Permanent link") There are two offerings for serving LLMs on Azure **Azure OpenAI** marimo.toml `[](#__codelineno-9-1)[ai.models] [](#__codelineno-9-2)chat_model = "azure/gpt-4.1-mini" [](#__codelineno-9-3)[](#__codelineno-9-4)[ai.azure] [](#__codelineno-9-5)api_key = "sk-proj-..." [](#__codelineno-9-6)base_url = "https://.openai.azure.com/openai/deployments/?api-version="` The deployment name is typically the model name. **Azure AI Foundry** AI Foundry uses OpenAI-compatible models. You can configure it as a custom provider: marimo.toml `[](#__codelineno-10-1)[ai.models] [](#__codelineno-10-2)custom_models = ["azure_foundry/mistral-medium"] [](#__codelineno-10-3)chat_model = "azure_foundry/mistral-medium" [](#__codelineno-10-4)[](#__codelineno-10-5)[ai.custom_providers.azure_foundry] [](#__codelineno-10-6)api_key = "sk-proj-..." [](#__codelineno-10-7)base_url = "https://.services.ai.azure.com/openai/v1"` ### GitHub Copilot[¶](#github-copilot "Permanent link") Use Copilot for code refactoring or the chat panel (Copilot subscription required). **Requirements** * Install the [gh CLI](https://cli.github.com/) * Get a token: `gh auth token` **Configuration** marimo.toml `[](#__codelineno-11-1)[ai.models] [](#__codelineno-11-2)chat_model = "github/gpt-4o-mini" [](#__codelineno-11-3)[](#__codelineno-11-4)[ai.github] [](#__codelineno-11-5)api_key = "gho_..."` My token starts with `ghp_` instead of `gho_`? This usually happens when you previously authenticated `gh` by pasting a _personal_ access token (`ghp_...`). However, GitHub Copilot is not available through `ghp_...`, and you will encounter errors such as: > bad request: Personal Access Tokens are not supported for this endpoint To resolve this issue, you could switch to an _OAuth_ access token (`gho_...`): 1. Re-authenticate by running `gh auth login`. 2. Choose _Login with a web browser_ (instead of _Paste an authentication token_) this time. ### OpenRouter[¶](#openrouter "Permanent link") Route to many providers through OpenRouter with a single API. **Requirements** * Create an API key: [OpenRouter Dashboard](https://openrouter.ai/) * `pip install openai` or `uv add openai` (OpenRouter is OpenAI‑compatible) **Configuration** marimo.toml `[](#__codelineno-12-1)[ai.models] [](#__codelineno-12-2)# Use OpenRouter's model slugs (vendor/model). Examples: [](#__codelineno-12-3)chat_model = "openrouter/openai/gpt-4o-mini" [](#__codelineno-12-4)edit_model = "openrouter/anthropic/claude-3-7-sonnet" [](#__codelineno-12-5)[](#__codelineno-12-6)[ai.openrouter] [](#__codelineno-12-7)api_key = "sk-or-..." [](#__codelineno-12-8)base_url = "https://openrouter.ai/api/v1/" [](#__codelineno-12-9)# Optional but recommended per OpenRouter best practices [](#__codelineno-12-10)# extra_headers = { "HTTP-Referer" = "https://your-app.example", "X-Title" = "Your App Name" }` See available models at `https://openrouter.ai/models`. Make sure to prepend `openrouter/` to the model slug (e.g., `openrouter/deepseek/deepseek-chat`, `openrouter/meta-llama/llama-3.1-8b-instruct`). ### Weights & Biases[¶](#weights-biases "Permanent link") Access hosted AI models through Weights & Biases Weave for ML development and inference. **Requirements** * Create an API key: [Weights & Biases Settings](https://wandb.ai/authorize) * `pip install openai` or `uv add openai` (Weights & Biases is OpenAI‑compatible) **Configuration** marimo.toml `[](#__codelineno-13-1)[ai.models] [](#__codelineno-13-2)# Use wandb/ prefix for Weights & Biases models. Examples: [](#__codelineno-13-3)chat_model = "wandb/meta-llama/llama-3-70b-instruct" [](#__codelineno-13-4)edit_model = "wandb/gpt-4o" [](#__codelineno-13-5)[](#__codelineno-13-6)[ai.wandb] [](#__codelineno-13-7)api_key = "your-wandb-api-key" [](#__codelineno-13-8)base_url = "https://api.inference.wandb.ai/v1/" # Optional, this is the default` See available models at the [Weights & Biases documentation](https://docs.wandb.ai/inference). Make sure to prepend `wandb/` to the model name. ### Local models with Ollama[¶](#using-ollama "Permanent link") Run open-source LLMs locally and connect via an OpenAI‑compatible API. **Requirements** * Install [Ollama](https://ollama.com/) * `pip install openai` or `uv add openai` **Setup** 1. Pull a model `[](#__codelineno-14-1)# View available models at https://ollama.com/library [](#__codelineno-14-2)ollama pull llama3.1 [](#__codelineno-14-3)ollama pull codellama # recommended for code generation [](#__codelineno-14-4)[](#__codelineno-14-5)# View your installed models [](#__codelineno-14-6)ollama ls` 2. Start the Ollama server: `[](#__codelineno-15-1)ollama serve [](#__codelineno-15-2)# In another terminal, run a model (optional) [](#__codelineno-15-3)ollama run codellama` 3. Visit [http://127.0.0.1:11434](http://127.0.0.1:11434/) to confirm that the server is running. Port already in use If you get a "port already in use" error, you may need to close an existing Ollama instance. On Windows, click the up arrow in the taskbar, find the Ollama icon, and select "Quit". This is a known issue (see [Ollama Issue #3575](https://github.com/ollama/ollama/issues/3575)). Once you've closed the existing Ollama instance, you should be able to run `ollama serve` successfully. **Configuration** marimo.toml `` [](#__codelineno-16-1)[ai.models] [](#__codelineno-16-2)chat_model = "ollama/llama3.1:latest" [](#__codelineno-16-3)edit_model = "ollama/codellama" [](#__codelineno-16-4)autocomplete_model = "ollama/codellama" # or another model from `ollama ls` `` Important: Use the `/v1` endpoint marimo uses Ollama's OpenAI‑compatible API. Ensure your `base_url` includes `/v1`: `[](#__codelineno-17-1)[ai.ollama] [](#__codelineno-17-2)base_url = "http://127.0.0.1:11434/v1" # ✅ Correct - includes /v1` Common mistake: `[](#__codelineno-18-1)base_url = "http://127.0.0.1:11434" # ❌ Will cause 404 errors` If you see 404s, verify the model is installed with `ollama ls` and test the endpoint: `[](#__codelineno-19-1)curl http://127.0.0.1:11434/v1/models` Custom providers[¶](#custom-providers "Permanent link") ------------------------------------------------------- Add multiple OpenAI-compatible providers through the Settings UI. Each custom provider gets its own configuration section and can be referenced by name in your model settings. The following section is a **non-exhaustive** list of supported providers. **Requirements** * Provider API key * Provider OpenAI-compatible `base_url` * `pip install openai` or `uv add openai` **Adding a custom provider via UI (recommended)** 1. Open marimo's Settings panel 2. Navigate to **AI** → **AI Providers** 3. Scroll to **Custom Providers** and click **Add Provider** 4. Navigate to the **AI Models** tab and select your custom provider. **Configuration via marimo.toml** You can also configure custom providers directly in `marimo.toml`: marimo.toml `[](#__codelineno-20-1)[ai.models] [](#__codelineno-20-2)chat_model = "groq/llama-3.1-70b-versatile" [](#__codelineno-20-3)edit_model = "together/meta-llama/Llama-3-70b-chat-hf" [](#__codelineno-20-4)[](#__codelineno-20-5)[ai.custom_providers.groq] [](#__codelineno-20-6)api_key = "gsk-..." [](#__codelineno-20-7)base_url = "https://api.groq.com/openai/v1" [](#__codelineno-20-8)[](#__codelineno-20-9)[ai.custom_providers.together] [](#__codelineno-20-10)api_key = "tg-..." [](#__codelineno-20-11)base_url = "https://api.together.xyz/v1" [](#__codelineno-20-12)[](#__codelineno-20-13)[ai.custom_providers.my_local_server] [](#__codelineno-20-14)base_url = "http://localhost:8000/v1"` Use the `/v1` path if required by your provider Some OpenAI-compatible providers expose their API under `/v1` (e.g., `https://host/v1`). If you see 404s, add `/v1` to your `base_url`. ### DeepSeek[¶](#deepseek "Permanent link") Use DeepSeek via its OpenAI‑compatible API. **Requirements** * DeepSeek API key **Configuration** marimo.toml `[](#__codelineno-21-1)[ai.models] [](#__codelineno-21-2)chat_model = "deepseek/deepseek-chat" # or "deepseek-reasoner" [](#__codelineno-21-3)[](#__codelineno-21-4)[ai.custom_providers.deepseek] [](#__codelineno-21-5)api_key = "dsk-..." [](#__codelineno-21-6)base_url = "https://api.deepseek.com/"` ### xAI[¶](#xai "Permanent link") Use Grok models via xAI's OpenAI‑compatible API. **Requirements** * xAI API key **Configuration** marimo.toml `[](#__codelineno-22-1)[ai.models] [](#__codelineno-22-2)chat_model = "xai/grok-2-latest" [](#__codelineno-22-3)[](#__codelineno-22-4)[ai.custom_providers.xai] [](#__codelineno-22-5)api_key = "xai-..." [](#__codelineno-22-6)base_url = "https://api.x.ai/v1/"` ### LM Studio[¶](#lm-studio "Permanent link") Connect to a local model served by LM Studio's OpenAI‑compatible endpoint. **Requirements** * Install LM Studio and start its server **Configuration** marimo.toml `[](#__codelineno-23-1)[ai.models] [](#__codelineno-23-2)chat_model = "lmstudio/qwen2.5-coder-7b" [](#__codelineno-23-3)[](#__codelineno-23-4)[ai.custom_providers.lmstudio] [](#__codelineno-23-5)base_url = "http://127.0.0.1:1234/v1" # LM Studio server` ### Mistral[¶](#mistral "Permanent link") Use Mistral via its OpenAI‑compatible API. **Requirements** * Mistral API key **Configuration** marimo.toml `[](#__codelineno-24-1)[ai.models] [](#__codelineno-24-2)chat_model = "mistral/mistral-small-latest" # e.g., codestral-latest, mistral-large-latest [](#__codelineno-24-3)[](#__codelineno-24-4)[ai.custom_providers.mistral] [](#__codelineno-24-5)api_key = "mistral-..." [](#__codelineno-24-6)base_url = "https://api.mistral.ai/v1/"` ### Together AI[¶](#together-ai "Permanent link") Access multiple hosted models via Together AI's OpenAI‑compatible API. **Requirements** * Together AI API key **Configuration** marimo.toml `[](#__codelineno-25-1)[ai.models] [](#__codelineno-25-2)chat_model = "together/mistralai/Mixtral-8x7B-Instruct-v0.1" [](#__codelineno-25-3)[](#__codelineno-25-4)[ai.custom_providers.together] [](#__codelineno-25-5)api_key = "tg-..." [](#__codelineno-25-6)base_url = "https://api.together.xyz/v1/"` ### Vercel v0[¶](#vercel-v0 "Permanent link") Use Vercel's v0 OpenAI‑compatible models for app-oriented generation. **Requirements** * v0 API key **Configuration** marimo.toml `[](#__codelineno-26-1)[ai.models] [](#__codelineno-26-2)chat_model = "v0/v0-1.5-md" [](#__codelineno-26-3)[](#__codelineno-26-4)[ai.custom_providers.v0] [](#__codelineno-26-5)api_key = "v0-..." [](#__codelineno-26-6)base_url = "https://api.v0.dev/" # Verify the endpoint in v0 docs` See the [LiteLLM provider list](https://litellm.vercel.app/docs/providers) for more options. For non‑compatible APIs, submit a [feature request](https://github.com/marimo-team/marimo/issues/new?template=feature_request.yaml). ### OpenAI-compatible (legacy)[¶](#openai-compatible-legacy "Permanent link") Prefer custom providers The `[ai.open_ai_compatible]` section is still supported for backward compatibility, but we recommend using **custom providers** instead, which allows you to configure multiple providers with distinct names. For a single OpenAI-compatible provider, you can use: marimo.toml `[](#__codelineno-27-1)[ai.models] [](#__codelineno-27-2)chat_model = "provider-x/some-model" [](#__codelineno-27-3)[](#__codelineno-27-4)[ai.open_ai_compatible] [](#__codelineno-27-5)api_key = "..." [](#__codelineno-27-6)base_url = "https://api.provider-x.com/"` Models that don't match a known provider prefix will fall back to this configuration. HTML head - marimo https://docs.marimo.io/guides/configuration/html_head/ Custom HTML Head[¶](#custom-html-head "Permanent link") ------------------------------------------------------- You can include a custom HTML head file to add additional functionality to your notebook, such as analytics, custom fonts, meta tags, or external scripts. The contents of this file will be injected into the `` section of your notebook. To include a custom HTML head file, specify the relative file path in your app configuration. This can be done through the marimo editor UI in the notebook settings (top-right corner). This will be reflected in your notebook file: `[](#__codelineno-0-1)app = marimo.App(html_head_file="head.html")` Example Use Cases[¶](#example-use-cases "Permanent link") --------------------------------------------------------- Here are some common use cases for custom HTML head content: 1. **Google Analytics** `[](#__codelineno-1-1) [](#__codelineno-1-2) [](#__codelineno-1-3) [](#__codelineno-1-4)` 2. **Custom Fonts** `[](#__codelineno-2-1) [](#__codelineno-2-2) [](#__codelineno-2-3) [](#__codelineno-2-4)` 3. **Meta Tags** `[](#__codelineno-3-1) [](#__codelineno-3-2) [](#__codelineno-3-3) [](#__codelineno-3-4) [](#__codelineno-3-5) [](#__codelineno-3-6) [](#__codelineno-3-7)` OpenGraph previews For common OpenGraph fields (title, description, image), you can also use notebook OpenGraph metadata in script metadata. See [OpenGraph previews](https://docs.marimo.io/guides/publishing/opengraph/). 4. **External Scripts and Libraries** `[](#__codelineno-4-1) [](#__codelineno-4-2) [](#__codelineno-4-3) [](#__codelineno-4-4) [](#__codelineno-4-5)[](#__codelineno-4-6) [](#__codelineno-4-7)` Theming - marimo https://docs.marimo.io/guides/configuration/theming/ marimo provides basic support for theming. You can include a custom CSS file in your notebook that will be applied to the entire notebook. This allows you to customize the appearance of your notebook to your liking. To include a custom CSS file, in the configuration dropdown, add the relative file path to your CSS file in the `Custom CSS` field. Once saved, you should see the changes applied to your notebook: `[](#__codelineno-0-1)app = marimo.App(css_file="custom.css")` Theming at the project level[¶](#theming-at-the-project-level "Permanent link") ------------------------------------------------------------------------------- You may also set the `custom_css` field in your project configuration to apply a custom CSS file. This theme won't be applied if the notebook is shared with someone else, but it will be applied to all notebooks open inside the project. pyproject.toml `[](#__codelineno-1-1)[tool.marimo.display] [](#__codelineno-1-2)custom_css = ["additional.css"]` CSS Variables[¶](#css-variables "Permanent link") ------------------------------------------------- We support only a few CSS variables as part of the "public API" for theming. These are: `[](#__codelineno-2-1)--marimo-monospace-font [](#__codelineno-2-2)--marimo-text-font [](#__codelineno-2-3)--marimo-heading-font` Other CSS Variables We cannot guarantee that other CSS variables or classnames will be stable across versions. Example[¶](#example "Permanent link") ------------------------------------- Here is an example of a custom CSS file that changes the font of the notebook: `[](#__codelineno-3-1)/* Load Inter from Google Fonts */ [](#__codelineno-3-2)@import url('https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap'); [](#__codelineno-3-3)[](#__codelineno-3-4):root { [](#__codelineno-3-5) --marimo-heading-font: 'Inter', sans-serif; [](#__codelineno-3-6)} [](#__codelineno-3-7)[](#__codelineno-3-8)/* Increase paragraph font size and change color */ [](#__codelineno-3-9).paragraph { [](#__codelineno-3-10) font-size: 1.2rem; [](#__codelineno-3-11) color: light-dark(navy, pink); [](#__codelineno-3-12)}` You can push custom CSS pretty far in marimo, check out [this demo on YouTube](https://www.youtube.com/shorts/GiMnWT_ZMOc) on how to create a custom theme based on [NES.css](https://nostalgic-css.github.io/NES.css/). Custom HTML Head[¶](#custom-html-head "Permanent link") ------------------------------------------------------- You can further customize your notebook by adding custom HTML in the `` section of your notebook. This allows you to add additional functionality to your notebook, such as analytics, custom fonts, meta tags, or external scripts. See the [Custom HTML Head](https://docs.marimo.io/guides/configuration/html_head/) guide for more details. Forcing dark mode[¶](#forcing-dark-mode "Permanent link") --------------------------------------------------------- In order to force a theme for an application, you can override the marimo configuration specifically for an application using the script metadata. See the [Script Configuration](https://docs.marimo.io/guides/configuration/#script-metadata-configuration) for more details. `[](#__codelineno-4-1)# /// script [](#__codelineno-4-2)# [tool.marimo.display] [](#__codelineno-4-3)# theme = "dark" [](#__codelineno-4-4)# ///` Targeting cells[¶](#targeting-cells "Permanent link") ----------------------------------------------------- You can target a cell's styles from the `data-cell-name` attribute. You can also target a cell's output with the `data-cell-role="output"` attribute. `[](#__codelineno-5-1)/* Target the cell named "My Cell" */ [](#__codelineno-5-2)[data-cell-name='my_cell'] { [](#__codelineno-5-3) background-color: light-dark(navy, pink); [](#__codelineno-5-4)} [](#__codelineno-5-5)[](#__codelineno-5-6)/* Target the output of the cell named "My Cell" */ [](#__codelineno-5-7)[data-cell-name='my_cell'] [data-cell-role='output'] { [](#__codelineno-5-8) background-color: light-dark(navy, pink); [](#__codelineno-5-9)}` The marimo community maintains a [library of custom themes](https://github.com/Haleshot/marimo-themes) that you can use in your notebooks. The library includes various themes like "coldme", "nord", "mininini", and "wigwam", each supporting both light and dark modes. You can: * Browse and download existing themes * Use them in your own notebooks * Contribute your own themes to share with the community Visit the [marimo-themes repository](https://github.com/Haleshot/marimo-themes) to explore available themes and learn how to contribute your own. More customizations[¶](#more-customizations "Permanent link") ------------------------------------------------------------- We want to hear from you! If you have any suggestions for more customization options, please let us know on [GitHub](https://github.com/marimo-team/marimo/discussions) Snippets - marimo https://docs.marimo.io/guides/configuration/snippets/ Snippets Configuration[¶](#snippets-configuration "Permanent link") ------------------------------------------------------------------- marimo provides a snippets feature that allows you to quickly insert commonly used code blocks into your notebooks. You can configure both the default snippets and add your own custom snippets. Configuration Options[¶](#configuration-options "Permanent link") ----------------------------------------------------------------- You can configure snippets through your `marimo.toml` file: `[](#__codelineno-0-1)[snippets] [](#__codelineno-0-2)custom_paths = ["/path/to/your/snippets/dir"] # List of paths to directories containing custom snippets [](#__codelineno-0-3)include_default_snippets = true # Whether to include marimo's default snippets (defaults to true)` Custom Snippets[¶](#custom-snippets "Permanent link") ----------------------------------------------------- To add your own snippets: 1. Create a directory to store your snippets 2. Add the directory path to the `custom_paths` list in your configuration 3. Create snippet files in your directory following the marimo snippet format ### Snippet Format[¶](#snippet-format "Permanent link") Snippets are Python files that follow a specific format. Each snippet should be a marimo notebook file with a title and code: Example snippet file (`my_snippet.py`): `[](#__codelineno-1-1)import marimo [](#__codelineno-1-2)[](#__codelineno-1-3)app = marimo.App(width="medium") [](#__codelineno-1-4)[](#__codelineno-1-5)@app.cell(hide_code=True) [](#__codelineno-1-6)def _(mo): [](#__codelineno-1-7) mo.md(r"""# Load .env""") [](#__codelineno-1-8) return [](#__codelineno-1-9) [](#__codelineno-1-10)[](#__codelineno-1-11)@app.cell [](#__codelineno-1-12)def _(): [](#__codelineno-1-13) import dotenv [](#__codelineno-1-14) [](#__codelineno-1-15) dotenv.load_dotenv(dotenv.find_dotenv(usecwd=True)) [](#__codelineno-1-16) return (dotenv,) [](#__codelineno-1-17) [](#__codelineno-1-18)[](#__codelineno-1-19)@app.cell [](#__codelineno-1-20)def _(): [](#__codelineno-1-21) import marimo as mo [](#__codelineno-1-22) return (mo,) [](#__codelineno-1-23) [](#__codelineno-1-24)[](#__codelineno-1-25)if __name__ == "__main__": [](#__codelineno-1-26) app.run()` Default Snippets[¶](#default-snippets "Permanent link") ------------------------------------------------------- marimo comes with a set of default snippets for common operations. You can disable the default snippets by setting `include_default_snippets = false` in your configuration. Extending marimo - marimo https://docs.marimo.io/guides/integrating_with_marimo/ Integrating with marimo[¶](#integrating-with-marimo "Permanent link") --------------------------------------------------------------------- These guides will help you integrate your objects with marimo and hook into marimo's reactive execution engine for UI plugins. Still need help? Reach out to us on [Discord](https://marimo.io/discord?ref=docs) or [GitHub issues](https://github.com/marimo-team/marimo/issues). Checking if running in a marimo notebook You can check if Python is running in a marimo notebook with [`mo.running_in_notebook`](https://docs.marimo.io/api/miscellaneous/#marimo.running_in_notebook " marimo.running_in_notebook"). This can be helpful when developing library code that integrates with marimo. | Guide | Description | | --- | --- | | [Displaying Objects](https://docs.marimo.io/guides/integrating_with_marimo/displaying_objects/) | Richly display objects by hooking into marimo's media viewer | | [Custom UI Plugins](https://docs.marimo.io/guides/integrating_with_marimo/custom_ui_plugins/) | Build custom UI plugins that hook into marimo's reactive execution engine | i18n - marimo https://docs.marimo.io/guides/configuration/internationalization/ Internationalization (i18n)[¶](#internationalization-i18n "Permanent link") --------------------------------------------------------------------------- marimo provides basic internationalization support through locale configuration. This primarily affects how dates, numbers, and relative times are formatted throughout the interface. What is localized[¶](#what-is-localized "Permanent link") --------------------------------------------------------- The `locale` setting configures formatting for: * **Date formatting**: How dates are displayed in data tables and outputs * **Datetime formatting**: How timestamps are displayed * **Number formatting**: How numbers are formatted (decimal separators, thousands separators) * **Relative times**: How relative time expressions like "Today at 8:00 AM" or "Yesterday at 2:30 PM" are displayed Text is not localized marimo does **not** localize UI text, error messages, or documentation as this requires significant effort which we currently cannot afford on our own. Configuration[¶](#configuration "Permanent link") ------------------------------------------------- You can configure the locale in three different ways, with the following precedence order: **Script config > pyproject.toml config > user config** ### User Settings[¶](#user-settings "Permanent link") Configure the locale globally for all notebooks through the Settings menu in the marimo editor: 1. Click the Settings button (⚙️) in the top-right corner 2. Navigate to the "Display" section 3. Set the "Locale" field to your desired locale (e.g., `en-US`, `fr-FR`, `de-DE`) This setting is stored in your user configuration file (`~/.config/marimo/marimo.toml` or similar). ### Project Configuration (pyproject.toml)[¶](#project-configuration-pyprojecttoml "Permanent link") For team projects, you can set the locale in your `pyproject.toml` file to ensure consistency across all team members: pyproject.toml `[](#__codelineno-0-1)[tool.marimo.display] [](#__codelineno-0-2)locale = "en-US"` This configuration will apply to all notebooks in the project and override individual user settings. ### Notebook Settings (Script Metadata)[¶](#notebook-settings-script-metadata "Permanent link") You can also configure the locale for a specific notebook using script metadata. Add this at the top of your notebook file: `[](#__codelineno-1-1)# /// script [](#__codelineno-1-2)# [tool.marimo.display] [](#__codelineno-1-3)# locale = "fr-FR" [](#__codelineno-1-4)# ///` This has the highest precedence and will override both project and user configurations for that specific notebook. Default behavior If no locale is configured, marimo will use the user's browser locale (detected from `navigator.language`). Supported locales[¶](#supported-locales "Permanent link") --------------------------------------------------------- The locale should follow the BCP 47 language tag format (`language-country`). Troubleshooting[¶](#troubleshooting "Permanent link") ----------------------------------------------------- If your locale setting isn't taking effect: 1. **Check the precedence**: Script metadata overrides pyproject.toml, which overrides user settings 2. **Verify the locale format**: Ensure you're using a valid BCP 47 language tag 3. **Restart marimo**: Some configuration changes may require restarting the marimo server 4. **Check browser support**: The locale must be supported by your browser's `Intl` API To verify your current configuration, run: This will display your active configuration including the current locale setting. Custom UI plugins - marimo https://docs.marimo.io/guides/integrating_with_marimo/custom_ui_plugins/ Build custom UI plugins that hook into marimo’s reactive execution engine by using [anywidget](https://anywidget.dev/). [See our AnyWidget API docs](https://docs.marimo.io/api/inputs/anywidget/) for more information. Coming from other tools - marimo https://docs.marimo.io/guides/coming_from/ marimo is a **single tool** that replaces `jupyter`, `streamlit`, `jupytext`, `ipywidgets`, `papermill`, and more. | Guide | Description | | --- | --- | | [Streamlit](https://docs.marimo.io/guides/coming_from/streamlit/) | Transitioning from Streamlit | | [Jupytext](https://docs.marimo.io/guides/coming_from/jupytext/) | Transitioning from Jupytext | | [Papermill](https://docs.marimo.io/guides/coming_from/papermill/) | Transitioning from Papermill | Coming from Jupyter? See our [coming from Jupyter guide](https://docs.marimo.io/guides/coming_from/jupyter/). Jupytext - marimo https://docs.marimo.io/guides/coming_from/jupytext/ Coming from Jupytext[¶](#coming-from-jupytext "Permanent link") --------------------------------------------------------------- If you're familiar with Jupytext, you'll find that marimo offers similar functionality for working with notebooks as Python files, but without the need for additional setup or synchronization issues because marimo notebooks are stored as `.py` files by default. However, Jupytext works with IPython notebooks, whereas marimo works with marimo notebooks, which are not based on IPython/Jupyter. Here's a comparison to help you transition smoothly. marimo also has a markdown fileformat Learn more by running `marimo tutorial markdown-format` at the command-line. Notebook Format[¶](#notebook-format "Permanent link") ----------------------------------------------------- | Jupytext | marimo | | --- | --- | | Jupytext uses comments or special markers to define cell types in notebooks. | Notebooks are pure Python (`.py`) files by default, using standard Python syntax, such as decorators and functions, to define cells. In markdown form (`.md`), marimo has no special syntax, meaning your notebook will render well in locations like Github. | Converting Jupyter notebooks[¶](#converting-jupyter-notebooks "Permanent link") ------------------------------------------------------------------------------- ### From `.ipynb`[¶](#from-ipynb "Permanent link") | Jupytext | marimo | | --- | --- | | `jupytext --to py notebook.ipynb` | `marimo convert notebook.ipynb > notebook.py` | From py:percent notebooks to marimo notebooks marimo can directly convert Python files in the [py:percent](https://jupytext.readthedocs.io/en/latest/#text-notebooks) format (requires jupytext): `[](#__codelineno-0-1)marimo convert percent_notebook.py -o marimo_notebook.py` If using uv: `[](#__codelineno-1-1)uvx --with=jupytext marimo convert percent_notebook.py -o marimo_notebook.py` ### To `.ipynb`[¶](#to-ipynb "Permanent link") | Jupytext | marimo | | --- | --- | | `jupytext --to notebook.ipynb notebook.py` | `marimo export ipynb notebook.py > notebook.ipynb` | Editing Notebooks[¶](#editing-notebooks "Permanent link") --------------------------------------------------------- | Jupytext | marimo | | --- | --- | | Requires synchronization between `.ipynb` and `.py` files. | Edit marimo notebooks files directly in the marimo editor (`marimo edit notebook.py`), and changes are read from and written to the same file. | Executing Notebooks[¶](#executing-notebooks "Permanent link") ------------------------------------------------------------- | Jupytext | marimo | | --- | --- | | Use Jupyter to edit notebooks interactively, or Papermill to execute notebooks from the command line. | In addition to running notebooks interactively (`marimo notebook.py`), you can run notebooks as scripts (`python notebook.py`) or as apps (`marimo run notebook.py`), passing values to them with marimo's built-in support for [CLI args](https://docs.marimo.io/api/cli_args/). | Version Control[¶](#version-control "Permanent link") ----------------------------------------------------- | Jupytext | marimo | | --- | --- | | Jupyter notebooks are stored as JSON by default, making them difficult to meaningfully version with git. Use Jupytext to pair and synchronize jupyter notebooks with text representations for smaller git diffs. | Notebooks are already in `.py` format, making them git-friendly by default. Small changes to the notebook are guaranteed to yield small diffs. | Markdown and Code Cells[¶](#markdown-and-code-cells "Permanent link") --------------------------------------------------------------------- | Jupytext | marimo | | --- | --- | | Uses special markers or formats to distinguish cell types. Magical syntax is required. | Uses `mo.md("...")` for Markdown content, and interpolate Python values with `mo.md(f"...")`; no magical syntax. | Deployment[¶](#deployment "Permanent link") ------------------------------------------- | Jupytext | marimo | | --- | --- | | Requires migrating to other libraries like Voila or Streamlit for deployment. | Can be deployed as interactive web apps with `marimo run`. | Displaying objects - marimo https://docs.marimo.io/guides/integrating_with_marimo/displaying_objects/ Richly display objects[¶](#richly-display-objects "Permanent link") ------------------------------------------------------------------- marimo has built-in rich representations of many objects, including native Python objects like lists and dicts as well as marimo objects like [UI elements](https://docs.marimo.io/guides/interactivity/) and libraries, including matplotlib, seaborn, Plotly, altair pandas, and more. These rich representations are displayed for the last expression of a cell, or when using [`mo.output.append`](https://docs.marimo.io/api/outputs/#marimo.output.append " marimo.output.append"). You can register rich displays with marimo for your own objects. You have three options: 1. Implement a `_display_()` method 2. Implement a `_mime_()` method 3. Implement an IPython-style `_repr_*_()` method If you can't modify the object, you can also add a formatter to the marimo library (option 4). The return value of these methods determines what is shown. `_display_` has the highest precedence, then built-in formatters, then `_mime_`, then `IPython` style `_repr_*_` methods. Option 1: Implement a `_display_()` method[¶](#option-1-implement-a-_display_-method "Permanent link") ------------------------------------------------------------------------------------------------------ If an object implements a `_display_()`, marimo will use its return value to visualize the object as an output. For example: `[](#__codelineno-0-1)class Dice: [](#__codelineno-0-2) def _display_(self): [](#__codelineno-0-3) import random [](#__codelineno-0-4) [](#__codelineno-0-5) return f"You rolled {random.randint(0, 7)}"` The return value of `_display_` can be any Python object, for example a a matplotlib plot, a dataframe, a list, `mo.Html`, or a `mo.ui` element, and marimo will attempt to display it. In addition to being the most convenient way do define a custom display in marimo (in terms of syntax), it is also helpful for library developers: this option lets you make an object showable in marimo without adding marimo as a dependency to your project. However, if you need to display an object that marimo does not know how to render (for example, maybe you are building a new plotting library), then you need to consider of the other options below. Option 2: Implement an IPython `_repr_*_()` method[¶](#option-2-implement-an-ipython-_repr__-method "Permanent link") --------------------------------------------------------------------------------------------------------------------- marimo can render objects that implement [IPython's `_repr_*_()` protocol](https://ipython.readthedocs.io/en/stable/config/integrating.html#custom-methods) for rich display. Here is an example of implementing `_repr_html_`, borrowed from IPython's documentation: `[](#__codelineno-1-1)class Shout: [](#__codelineno-1-2) def __init__(self, text): [](#__codelineno-1-3) self.text = text [](#__codelineno-1-4) [](#__codelineno-1-5) def _repr_html_(self): [](#__codelineno-1-6) return "

" + self.text + "

"` We support the following methods: * `_repr_html_` * `_repr_mimebundle_` * `_repr_svg_` * `_repr_json_` * `_repr_png_` * `_repr_jpeg_` * `_repr_markdown_` * `_repr_latex_` * `_repr_text_` **Note:** marimo currently does not handle any optional metadata returned by `_repr_mimebundle_`. Option 3: Implement a `_mime_` method[¶](#option-3-implement-a-_mime_-method "Permanent link") ---------------------------------------------------------------------------------------------- When displaying an object, marimo's media viewer checks for the presence of a method called `_mime_`. This method should take no arguments and return a tuple of two strings, the [mime type](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types) and data to be displayed as a string. **Examples.** Option 4: Add a formatter to the marimo repo[¶](#option-4-add-a-formatter-to-the-marimo-repo "Permanent link") -------------------------------------------------------------------------------------------------------------- The recommended way to render rich displays of objects in marimo is to implement `_display_` if possible, otherwise either the IPython `_repr_*_()_` protocol or marimo's `_mime_()` protocol. If you are a a user of a library that does not render properly in marimo, consider asking the library maintainers to implement one of these protocols. If it is not possible to implement a renderer protocol on the type you want displayed, we will consider contributions to add formatters to the marimo codebase. [Look at our codebase for examples](https://github.com/marimo-team/marimo/tree/main/marimo/_output/formatters), then open a pull request.
Streamlit - marimo https://docs.marimo.io/guides/coming_from/streamlit/ Coming from Streamlit[¶](#coming-from-streamlit "Permanent link") ----------------------------------------------------------------- If you're familiar with Streamlit and looking to transition to marimo, read on. The biggest difference between Streamlit and marimo is that Streamlit can only be used for data apps, whereas marimo is a notebook-first programming environment that makes it effortless to run notebooks as apps. In addition, marimo is much more performant than streamlit. Key Differences[¶](#key-differences "Permanent link") ----------------------------------------------------- 1. **Notebook vs. App Framework**: - marimo is primarily a reactive notebook environment, while Streamlit is an app framework. - marimo notebooks can be run as apps -- often with better performance than streamlit apps -- but they're designed with a notebook-first approach. - When creating streamlit apps, it is common to first prototype them as Jupyter notebooks, then migrate and refactor them into streamlit apps. With marimo, every notebook is automatically an app; there's no migration step needed. 2. **Performance.** - marimo uses a reactive execution model that, on interaction or code change, runs the minimal subset of notebook code needed to keep your notebook up-to-date. - Streamlit reruns the entire script on each interaction, which frequently causes performance issues. 3. **File Format**: * marimo notebooks and Streamlit apps are pure Python files (.py). * marimo's structure allows for more fine-grained reactivity. * Unlike streamlit files, marimo files can be executed as Python scripts from the command-line, and can be imported and used as a module by other Python programs. For example, other programs can [reuse cells](https://docs.marimo.io/api/cell/#marimo.Cell.run " run") from a marimo notebook. 4. **UI Elements**: * Both offer UI elements like sliders, text fields, and tables. * In streamlit, creating a UI element automatically outputs it to the display. -In marimo, the creation of a UI element is separated from its display, meaning that you can easily create custom layouts and higher-order elements, and even emit the same UI element twice. * marimo support the [anywidget](https://anywidget.dev/) spec for custom UI components, letting you reuse widgets that were originally developed for the Jupyter ecosystem, * streamlit has its own system for creating custom components. 5. **Built-in Editor**: * marimo includes a [built-in editor](https://docs.marimo.io/guides/editor_features/) for notebooks, designed specifically for working with data. * Streamlit relies on external editors. * Both approaches have their pros and cons. 6. **Working with data.**: * marimo's notebook environment allows for iterative and interactive development and exploration, letting it serve as your daily driver for working with data. marimo even has native support for [SQL](https://docs.marimo.io/guides/working_with_data/sql/). * Streamlit is exclusively used for building standalone data apps. Common Streamlit Features in marimo[¶](#common-streamlit-features-in-marimo "Permanent link") --------------------------------------------------------------------------------------------- ### 1\. Displaying text[¶](#1-displaying-text "Permanent link") Streamlit: `[](#__codelineno-0-1)import streamlit as st [](#__codelineno-0-2)st.markdown( [](#__codelineno-0-3) """ [](#__codelineno-0-4) # Greetings [](#__codelineno-0-5) Hello world [](#__codelineno-0-6) """ [](#__codelineno-0-7))` marimo: `[](#__codelineno-1-1)import marimo as mo [](#__codelineno-1-2)mo.md( [](#__codelineno-1-3) """ [](#__codelineno-1-4) # Greetings [](#__codelineno-1-5) Hello world [](#__codelineno-1-6) """ [](#__codelineno-1-7))` ### 2\. Displaying Data[¶](#2-displaying-data "Permanent link") Streamlit: marimo: `[](#__codelineno-3-1)df # Last expression in a cell is automatically displayed` ### 3\. Input Widgets[¶](#3-input-widgets "Permanent link") Streamlit: `[](#__codelineno-4-1)age = st.slider("How old are you?", 0, 130, 25)` marimo: `[](#__codelineno-5-1)age = mo.ui.slider(label="How old are you?", start=0, stop=130, value=25) [](#__codelineno-5-2)mo.md(f"One more question: {age}") # marimo can achieve more advanced composition` ### 4\. Buttons[¶](#4-buttons "Permanent link") Streamlit: `[](#__codelineno-6-1)if st.button("Click me"): [](#__codelineno-6-2) st.write("Button clicked!")` marimo: `[](#__codelineno-7-1)button = mo.ui.run_button("Click me")` `[](#__codelineno-8-1)# In another cell [](#__codelineno-8-2)if button.value: [](#__codelineno-8-3) mo.output.replace(mo.md("Button clicked!"))` `[](#__codelineno-9-1)# Or [](#__codelineno-9-2)mo.md("Button clicked!") if button.value else None` ### 5\. Layouts[¶](#5-layouts "Permanent link") Streamlit: `[](#__codelineno-10-1)col1, col2 = st.columns(2) [](#__codelineno-10-2)with col1: [](#__codelineno-10-3) st.write("Column 1") [](#__codelineno-10-4)with col2: [](#__codelineno-10-5) st.write("Column 2")` marimo: `[](#__codelineno-11-1)mo.hstack([ [](#__codelineno-11-2) mo.md("Column 1"), [](#__codelineno-11-3) mo.md("Column 2") [](#__codelineno-11-4)])` ### 6\. Advanced Layouts (tabs, accordions)[¶](#6-advanced-layouts-tabs-accordions "Permanent link") Streamlit: `[](#__codelineno-12-1)with st.expander("Expand me"): [](#__codelineno-12-2) st.write("Hello from the expander!")` marimo: `[](#__codelineno-13-1)mo.accordion({"Expand me": "Hello from the expander!"})` marimo's unique approach to composition allows for more flexible layouts with unlimited nesting. ### 6\. Plotting[¶](#6-plotting "Permanent link") Streamlit: `[](#__codelineno-14-1)import matplotlib.pyplot as plt [](#__codelineno-14-2)[](#__codelineno-14-3)fig, ax = plt.subplots() [](#__codelineno-14-4)ax.plot([1, 2, 3, 4]) [](#__codelineno-14-5)st.pyplot(fig)` marimo: `[](#__codelineno-15-1)import matplotlib.pyplot as plt [](#__codelineno-15-2)[](#__codelineno-15-3)plt.plot([1, 2, 3, 4]) [](#__codelineno-15-4)plt.gca() # Last expression is displayed` ### 7\. Caching[¶](#7-caching "Permanent link") Streamlit: `[](#__codelineno-16-1)@st.cache_data [](#__codelineno-16-2)def expensive_computation(args): [](#__codelineno-16-3) # ...` marimo: `[](#__codelineno-17-1)@mo.cache [](#__codelineno-17-2)def expensive_computation(args): [](#__codelineno-17-3) # ...` marimo provides [`mo.cache`](https://docs.marimo.io/api/caching/#marimo.cache) and [`mo.lru_cache`](https://docs.marimo.io/api/caching/#marimo.lru_cache) for caching function return values, as well as [`mo.persistent_cache`](https://docs.marimo.io/api/caching/#marimo.persistent_cache) for caching variables to disk. ### 8\. Session State[¶](#8-session-state "Permanent link") Streamlit uses `st.session_state` for persisting data. In marimo, you can use regular Python variables, as the notebook maintains consistent state for cells that are not re-executed. ### 9\. Running as an App[¶](#9-running-as-an-app "Permanent link") Streamlit: `[](#__codelineno-18-1)streamlit run your_app.py` marimo: `[](#__codelineno-19-1)marimo run your_notebook.py` Key Concepts to Remember[¶](#key-concepts-to-remember "Permanent link") ----------------------------------------------------------------------- 1. In marimo, cells are automatically re-executed when their dependencies change. But only the affected cells are re-executed, making it far more efficient than a naively written streamlit program. 2. UI elements in marimo are typically assigned to variables and their values accessed via the `value` attribute. 3. marimo's `mo.md()` function is versatile and can include both text and UI elements with f-strings. 4. marimo's notebook-first approach allows it to be used for all kinds of data work, including exploratory data analysis, data engineering, machine learning experimentation and model training, library documentation and examples, and more. Papermill - marimo https://docs.marimo.io/guides/coming_from/papermill/ Coming from Papermill[¶](#coming-from-papermill "Permanent link") ----------------------------------------------------------------- marimo provides built-in support for parametrizing and executing marimo notebooks. If you're familiar with Papermill, this guide will help you understand how to achieve similar functionality using marimo's features. Parameterizing Notebooks[¶](#parameterizing-notebooks "Permanent link") ----------------------------------------------------------------------- **Papermill** Papermill allows you to parameterize Jupyter notebooks by defining a "parameters" cell and injecting values at runtime. **marimo** marimo offers two main ways to parameterize notebooks: 1. **Command Line Arguments**: Use [`mo.cli_args`](https://docs.marimo.io/api/cli_args/) to access command-line arguments passed to your notebook. `[](#__codelineno-0-1)import marimo as mo [](#__codelineno-0-2)[](#__codelineno-0-3)# Access CLI args [](#__codelineno-0-4)args = mo.cli_args() [](#__codelineno-0-5)param1 = args.get("param1", "default_value")` Run your notebook as a script with: `[](#__codelineno-1-1)python notebook.py -- --param1 value1` Run your notebook as an app with: `[](#__codelineno-2-1)marimo run notebook.py -- --param1 value1` 2. **Query Parameters**: For web apps, use `mo.query_params` to access URL query parameters. `[](#__codelineno-3-1)import marimo as mo [](#__codelineno-3-2)[](#__codelineno-3-3)# Access query params [](#__codelineno-3-4)params = mo.query_params() [](#__codelineno-3-5)param1 = params.get("param1", "default_value")` Access your app with: Then visit: `[](#__codelineno-5-1)http://your-app-url/?param1=value1` Executing Notebooks[¶](#executing-notebooks "Permanent link") ------------------------------------------------------------- **Papermill** Papermill allows you to execute notebooks programmatically and pass parameters. **marimo** marimo notebooks are pure Python files, making them easy to execute programmatically. 1. **Running a named cell**: After naming a cell in your file, you can run it using the [cell execution API](https://docs.marimo.io/api/cell/#marimo.Cell.run " run"). `[](#__codelineno-6-1)from my_notebook import my_cell [](#__codelineno-6-2)[](#__codelineno-6-3)# last_expression is the visual output of the cell [](#__codelineno-6-4)# definitions is a dictionary of the variables defined by the cell [](#__codelineno-6-5)last_expression, definitions = my_cell.run()` This API also allows for parametrizing the inputs to the cell; to learn more, make sure to checkout [the example](https://docs.marimo.io/api/cell/#marimo.Cell.run " run") in our API reference. 2. **Programmatic execution with definition overrides**: You can run a marimo app programmatically and override cell definitions: `[](#__codelineno-7-1)import marimo [](#__codelineno-7-2)from my_notebook import app [](#__codelineno-7-3)[](#__codelineno-7-4)# Run the app with overridden definitions [](#__codelineno-7-5)# This completely replaces the definitions in cells that define these variables [](#__codelineno-7-6)outputs, defs = app.run(defs={"batch_size": 64, "learning_rate": 0.001, "model_type": "transformer"})` **Important limitations:** - When you provide definitions to `app.run()`, you are **completely overriding** the definitions of cells that define those variables - The cells that originally defined those variables will not execute their logic - You must provide **all** the definitions that a cell would normally produce, not just individual parameters - This is different from CLI arguments which are parsed within the cell's execution For example, if you have a cell that defines: `[](#__codelineno-8-1)@app.cell [](#__codelineno-8-2)def config(): [](#__codelineno-8-3) batch_size = 32 [](#__codelineno-8-4) learning_rate = 0.01 [](#__codelineno-8-5) return batch_size, learning_rate` To override this cell, you must provide both variables: `[](#__codelineno-9-1)# Correct: Override the entire cell's definitions [](#__codelineno-9-2)outputs, defs = app.run(defs={"batch_size": 64, "learning_rate": 0.001}) [](#__codelineno-9-3)[](#__codelineno-9-4)# Incorrect: This would leave learning_rate undefined [](#__codelineno-9-5)# outputs, defs = app.run(defs={"batch_size": 64})` 3. **Using subprocess**: `[](#__codelineno-10-1)import subprocess [](#__codelineno-10-2)[](#__codelineno-10-3)subprocess.run(["python", "notebook.py", "--", "--param1", "value1"])` Storing or Sharing Artifacts[¶](#storing-or-sharing-artifacts "Permanent link") ------------------------------------------------------------------------------- **Papermill** Papermill can store executed notebooks with output. **marimo** marimo offers several options for storing and sharing outputs: 1. **Export to HTML**: `[](#__codelineno-11-1)marimo export html notebook.py -o notebook.html -- -arg1 foo --arg2 bar` 2. **Deploy as Web App**: 3. **Auto-export HTML**: You can configure marimo to automatically export to HTML during the editing process. This is configured in the marimo application settings directly in the editor. This way, after changes are made to your notebook, an HTML snapshot is generated, and placed in a `.marimo/` directory in the same location as your notebook. Workflow Integration[¶](#workflow-integration "Permanent link") --------------------------------------------------------------- **Papermill** Papermill is often used in data pipelines and workflow systems. **marimo** marimo notebooks can be easily integrated into workflows: 1. **As Python Scripts**: marimo notebooks are Python files, so they can be executed directly in most workflow systems. See [our examples](https://github.com/marimo-team/marimo/tree/main/examples) for integrating with popular tools. 2. **Programmatic Execution**: Importing notebook as Python modules or executing via subprocess allows for chaining together multiple notebooks in a workflow. Best practices - marimo https://docs.marimo.io/guides/best_practices/ Here are best practices for writing marimo notebooks. **Use global variables sparingly.** Keep the number of global variables in your program small to avoid name collisions. If you have intermediate variables, encapsulate them in functions or prefix them with an underscore (`_tmp = ...`) to make them local to a cell. **Use descriptive names.** Use descriptive variable names, especially for global variables. This will help you minimize name clashes, and will also result in better code. **Use functions.** Encapsulate logic into functions to avoid polluting the global namespace with temporary or intermediate variables, and to avoid code duplication. **Use [`mo.stop`](https://docs.marimo.io/api/control_flow/#marimo.stop " marimo.stop") to stop execution.** Use [`mo.stop`](https://docs.marimo.io/api/control_flow/#marimo.stop " marimo.stop") to stop a cell from running when a condition is true; this is helpful when working with expensive notebooks. For example, prevent a cell from running until a button is clicked using [`mo.ui.run_button`](https://docs.marimo.io/api/inputs/run_button/#marimo.ui.run_button " marimo.ui.run_button") and [`mo.stop`](https://docs.marimo.io/api/control_flow/#marimo.stop " marimo.stop"). Expensive notebooks For more tips on working with expensive notebooks, see the associated [guide](https://docs.marimo.io/guides/expensive_notebooks/). **Use Python modules.** If your notebook gets too long, split complex logic into helper Python modules and import them into your notebook. Use marimo's built-in [module reloading](https://docs.marimo.io/guides/configuration/runtime_configuration/#on-module-change) to automatically bring changes from your modules into your notebook. **Minimize mutations.** marimo does not track mutations to objects. Try to only mutate an object in the cell that creates it, or create new objects instead of mutating existing ones. Example _Don't_ split up declarations and mutations over multiple cells. For example, _don't do this:_ Instead, _do_ **declare and mutate in the same cell**: `[](#__codelineno-2-1)l = [1, 2, 3] [](#__codelineno-2-2)... [](#__codelineno-2-3)l.append(new_item())` or, if working in multiple cells, **declare a new variable based on the old one**: `[](#__codelineno-4-1)extended_list = l + [new_item()]` **Don't use state and `on_change` handlers.** Don't use `on_change` handlers to react to UI interactions. Instead, use marimo's built-in [reactive execution for interactive elements](https://docs.marimo.io/guides/interactivity/). **Write idempotent cells.** Write cells whose outputs and behavior are the same when given the same inputs (references); such cells are called idempotent. This will help you avoid bugs and cache expensive intermediate computations. Lint Rules - marimo https://docs.marimo.io/guides/lint_rules/ marimo includes a linter that helps you write better notebooks. The linter checks for various issues that could prevent your notebook from running correctly or cause confusion. Usage[¶](#usage "Permanent link") --------------------------------- Run the linter using the CLI: `[](#__codelineno-0-1)# Check all notebooks in current directory [](#__codelineno-0-2)marimo check . [](#__codelineno-0-3)[](#__codelineno-0-4)# Check specific files [](#__codelineno-0-5)marimo check notebook1.py notebook2.py [](#__codelineno-0-6)[](#__codelineno-0-7)# Auto-fix fixable issues [](#__codelineno-0-8)marimo check --fix .` Rule Categories[¶](#rule-categories "Permanent link") ----------------------------------------------------- marimo's lint rules are organized into three main categories based on their severity: ### 🚨 Breaking Rules[¶](#breaking-rules "Permanent link") These errors prevent notebook execution. | Code | Name | Description | Fixable | | --- | --- | --- | --- | | [MB001](https://docs.marimo.io/guides/lint_rules/rules/unparsable_cells/) | unparsable-cells | Cell contains unparsable code | ❌ | | [MB002](https://docs.marimo.io/guides/lint_rules/rules/multiple_definitions/) | multiple-definitions | Multiple cells define the same variable | ❌ | | [MB003](https://docs.marimo.io/guides/lint_rules/rules/cycle_dependencies/) | cycle-dependencies | Cells have circular dependencies | ❌ | | [MB004](https://docs.marimo.io/guides/lint_rules/rules/setup_cell_dependencies/) | setup-cell-dependencies | Setup cell cannot have dependencies | ❌ | | [MB005](https://docs.marimo.io/guides/lint_rules/rules/invalid_syntax/) | invalid-syntax | Cell contains code that throws a SyntaxError on compilation | ❌ | ### ⚠️ Runtime Rules[¶](#runtime-rules "Permanent link") These issues may cause runtime problems. | Code | Name | Description | Fixable | | --- | --- | --- | --- | | [MR001](https://docs.marimo.io/guides/lint_rules/rules/self_import/) | self-import | Importing a module with the same name as the file | ❌ | | [MR002](https://docs.marimo.io/guides/lint_rules/rules/branch_expression/) | branch-expression | Branch statements with output expressions that won't be displayed | ❌ | ### ✨ Formatting Rules[¶](#formatting-rules "Permanent link") These are style and formatting issues. | Code | Name | Description | Fixable | | --- | --- | --- | --- | | [MF001](https://docs.marimo.io/guides/lint_rules/rules/general_formatting/) | general-formatting | General formatting issues with the notebook format. | 🛠️ | | [MF002](https://docs.marimo.io/guides/lint_rules/rules/parse_stdout/) | parse-stdout | Parse captured stdout during notebook loading | ❌ | | [MF003](https://docs.marimo.io/guides/lint_rules/rules/parse_stderr/) | parse-stderr | Parse captured stderr during notebook loading | ❌ | | [MF004](https://docs.marimo.io/guides/lint_rules/rules/empty_cells/) | empty-cells | Empty cells that can be safely removed. | ⚠️ | | [MF005](https://docs.marimo.io/guides/lint_rules/rules/sql_parse_error/) | sql-parse-error | SQL parsing errors during dependency analysis | ❌ | | [MF006](https://docs.marimo.io/guides/lint_rules/rules/misc_log_capture/) | misc-log-capture | Miscellaneous log messages during processing | ❌ | | [MF007](https://docs.marimo.io/guides/lint_rules/rules/markdown_indentation/) | markdown-indentation | Markdown cells in `mo.md()` should be properly indented. | 🛠️ | Legend[¶](#legend "Permanent link") ----------------------------------- * 🛠️ = Automatically fixable with `marimo check --fix` * ⚠️ = Fixable with `marimo check --fix --unsafe-fixes` (may change code behavior) * ❌ = Not automatically fixable Configuration[¶](#configuration "Permanent link") ------------------------------------------------- Most lint rules are enabled by default. You can configure the linter behavior through marimo's configuration system. * [Understanding Errors](https://docs.marimo.io/guides/understanding_errors/) - Detailed explanations of common marimo errors * [CLI Reference](https://docs.marimo.io/cli/) - Complete CLI documentation including `marimo check` Unparsable cells - marimo https://docs.marimo.io/guides/lint_rules/rules/unparsable_cells/ 🚨 **Breaking** ❌ Not Fixable MB001: Cell contains unparsable code. What it does[¶](#what-it-does "Permanent link") ----------------------------------------------- Identifies cells that cannot be parsed into valid Python AST nodes, indicating fundamental syntax or encoding problems that prevent the notebook from being loaded. Why is this bad?[¶](#why-is-this-bad "Permanent link") ------------------------------------------------------ Unparsable cells prevent the notebook from running as a script and will throw errors when executed in notebook mode. While marimo can still open the notebook, these cells cannot be run until the parsing issues are resolved. Examples[¶](#examples "Permanent link") --------------------------------------- **Problematic:** `[](#__codelineno-0-1)# Cell with encoding issues or corrupt data [](#__codelineno-0-2)x = 1 \x00\x01\x02 # Binary data in source` **Problematic:** `[](#__codelineno-1-1)# Cell with fundamental syntax errors [](#__codelineno-1-2)def func( [](#__codelineno-1-3) # Missing closing parenthesis and body` **Solution:** `[](#__codelineno-2-1)# Fix syntax errors and encoding issues [](#__codelineno-2-2)def func(): [](#__codelineno-2-3) return 42` References[¶](#references "Permanent link") ------------------------------------------- * [Understanding Errors](https://docs.marimo.io/guides/understanding_errors/) Multiple definitions - marimo https://docs.marimo.io/guides/lint_rules/rules/multiple_definitions/ 🚨 **Breaking** ❌ Not Fixable MB002: Multiple cells define the same variable. What it does[¶](#what-it-does "Permanent link") ----------------------------------------------- Analyzes the dependency graph to detect variables that are defined in more than one cell, which violates marimo's fundamental constraint for reactive execution. Why is this bad?[¶](#why-is-this-bad "Permanent link") ------------------------------------------------------ Multiple definitions prevent marimo from: - Determining the correct execution order - Creating a reliable dependency graph - Running notebooks as scripts - Providing consistent reactive updates This is a breaking error because it makes the notebook non-executable. Examples[¶](#examples "Permanent link") --------------------------------------- **Problematic:** `[](#__codelineno-0-1)# Cell 1 [](#__codelineno-0-2)x = 1 [](#__codelineno-0-3)[](#__codelineno-0-4)# Cell 2 [](#__codelineno-0-5)x = 2 # Error: x defined in multiple cells` **Solution:** `[](#__codelineno-1-1)# Cell 1 [](#__codelineno-1-2)x = 1 [](#__codelineno-1-3)[](#__codelineno-1-4)# Cell 2 [](#__codelineno-1-5)y = 2 # Use different variable name` References[¶](#references "Permanent link") ------------------------------------------- * [Multiple Definitions Guide](https://docs.marimo.io/guides/understanding_errors/multiple_definitions/) * [Understanding Errors](https://docs.marimo.io/guides/understanding_errors/) Debugging - marimo https://docs.marimo.io/guides/debugging/ In the marimo editor[¶](#in-the-marimo-editor "Permanent link") --------------------------------------------------------------- ### Setting breakpoints with pdb[¶](#setting-breakpoints-with-pdb "Permanent link") marimo supports pdb, the Python debugger. Set breakpoints in your code using the built-in `breakpoint()` function. When the code execution reaches a breakpoint, it will pause, and you can inspect variables, step through the code, and evaluate expressions. Here's a live example of how to use `breakpoint()` in a marimo notebook cell. Type `help` in the debugger for a list of commands. The debugger blocks execution When the debugger is active, you cannot execute cells. Remember to continue or quit the debugger to avoid hanging the notebook! Adding breakpoints in the stack trace Click the little bug icon in the stack trace to add breakpoints. Clicking on the cell link will also take you to the cell where the error occurred. ### Postmortem debugging[¶](#postmortem-debugging "Permanent link") If your code raises an exception, you can use postmortem debugging to inspect the state of the program at the point where the exception occurred. Click on the "Launch debugger" button as shown below: Debugging notebooks as scripts[¶](#debugging-notebooks-as-scripts "Permanent link") ----------------------------------------------------------------------------------- Since marimo notebooks are standard Python files, you can run them as scripts from the command line. The following command will run your marimo notebook and drop you into the pdb debugger if an exception occurs, or if you hit a breakpoint. `[](#__codelineno-1-1)python -m pdb your_script.py` Debugging with AI[¶](#debugging-with-ai "Permanent link") --------------------------------------------------------- marimo provides built-in integration with AI assistants to help you debug your notebooks. ### Ask about notebook errors[¶](#ask-about-notebook-errors "Permanent link") When interacting with the AI chat, you can reference the notebook "Errors" with the `@-symbol` to bring in comprehensive error information from your notebook, making it easier to get targeted debugging help. ### Best practices for AI-assisted debugging[¶](#best-practices-for-ai-assisted-debugging "Permanent link") **Provide context beyond just the error.** Include information about: - What you were trying to accomplish - Recent changes you made to the notebook - Whether the error is new or recurring - Related cells that might be involved **Leverage marimo's debugging tools alongside AI.** Use marimo's [dataflow tools](https://docs.marimo.io/guides/troubleshooting/#verify-cell-connections) to understand cell relationships, then share this information with AI assistants for more targeted advice. **Ask specific questions.** Instead of "Why is this broken?", try: - "Why might this reactivity issue be occurring between these cells?" - "How can I fix this import error in my marimo notebook?" - "What's the best way to debug this performance issue in my data processing pipeline?" Tip AI assistants are particularly helpful for explaining marimo-specific concepts like reactive execution, cell dependencies, and the differences between marimo notebooks and traditional Jupyter notebooks. Integrating with external IDEs[¶](#integrating-with-external-ides "Permanent link") ----------------------------------------------------------------------------------- marimo supports debugging with IDEs, like VS Code, which natively support the `debugpy` library. This allows you to set breakpoints, step through code, and inspect variables directly from your IDE. ### Running as scripts[¶](#running-as-scripts "Permanent link") You can debug marimo notebooks in VS Code using the following `launch.json`. This launch configuration will debug a marimo notebook executing it as a [script](https://docs.marimo.io/guides/scripts/). `[](#__codelineno-2-1){ [](#__codelineno-2-2) "version": "0.2.0", [](#__codelineno-2-3) "configurations": [ [](#__codelineno-2-4) { [](#__codelineno-2-5) "type": "python", [](#__codelineno-2-6) "request": "launch", [](#__codelineno-2-7) "name": "marimo Debug: script mode", [](#__codelineno-2-8) "program": "${file}", [](#__codelineno-2-9) "debugOptions": [ [](#__codelineno-2-10) "--ignore", "*/site-packages/marimo/*" [](#__codelineno-2-11) ] [](#__codelineno-2-12) }, [](#__codelineno-2-13) ] [](#__codelineno-2-14)}` ### Interactive development[¶](#interactive-development "Permanent link") Edit mode debugging allows the marimo editor to trigger breakpoints set in an IDE like VS Code. Running in this mode will automatically start your notebook in [watch mode](https://docs.marimo.io/guides/editor_features/watching/). Note that the file state and editor must be consistent for break points to correctly work. If debugging is not acting as expected, force a notebook save and toggle the relevant breakpoints. Use the following `launch.json` configuration to enable edit mode debugging: `[](#__codelineno-3-1){ [](#__codelineno-3-2) "version": "0.2.0", [](#__codelineno-3-3) "configurations": [ [](#__codelineno-3-4) { [](#__codelineno-3-5) "type": "debugpy", [](#__codelineno-3-6) "request": "launch", [](#__codelineno-3-7) "name": "marimo Debug: edit mode", [](#__codelineno-3-8) "program": "${file}", [](#__codelineno-3-9) "console": "integratedTerminal", [](#__codelineno-3-10) "cwd": "${workspaceFolder}", [](#__codelineno-3-11) "env": { [](#__codelineno-3-12) "MARIMO_SCRIPT_EDIT": "1" [](#__codelineno-3-13) }, [](#__codelineno-3-14) "justMyCode": false [](#__codelineno-3-15) } [](#__codelineno-3-16) ] [](#__codelineno-3-17)}` Note This will disable marimo's internal debugging features. Danger This mode is blocking in VS Code, so you will need to interact with the debugger in your editor to regain control of the marimo notebook. Cycle dependencies - marimo https://docs.marimo.io/guides/lint_rules/rules/cycle_dependencies/ 🚨 **Breaking** ❌ Not Fixable MB003: Cells have circular dependencies. What it does[¶](#what-it-does "Permanent link") ----------------------------------------------- Analyzes the dependency graph to detect circular references between cells, where cells depend on each other in a way that creates an impossible execution order. Why is this bad?[¶](#why-is-this-bad "Permanent link") ------------------------------------------------------ Circular dependencies prevent marimo from: - Determining a valid execution order - Running notebooks reproducibly - Executing notebooks as scripts - Providing reliable reactive updates This is a breaking error because it makes the notebook non-executable. Examples[¶](#examples "Permanent link") --------------------------------------- **Problematic:** `[](#__codelineno-0-1)# Cell 1 [](#__codelineno-0-2)a = b + 1 # Reads b [](#__codelineno-0-3)[](#__codelineno-0-4)# Cell 2 [](#__codelineno-0-5)b = a + 1 # Reads a -> Cycle!` **Solution:** `[](#__codelineno-1-1)# Cell 1 [](#__codelineno-1-2)a = 1 [](#__codelineno-1-3)[](#__codelineno-1-4)# Cell 2 [](#__codelineno-1-5)b = a + 1 # Unidirectional dependency` References[¶](#references "Permanent link") ------------------------------------------- * [Cycles Guide](https://docs.marimo.io/guides/understanding_errors/cycles/) * [Understanding Errors](https://docs.marimo.io/guides/understanding_errors/) Setup cell dependencies - marimo https://docs.marimo.io/guides/lint_rules/rules/setup_cell_dependencies/ 🚨 **Breaking** ❌ Not Fixable MB004: Setup cell cannot have dependencies. What it does[¶](#what-it-does "Permanent link") ----------------------------------------------- Validates that the setup cell (if present) does not depend on variables defined in other cells, ensuring proper execution order. Why is this bad?[¶](#why-is-this-bad "Permanent link") ------------------------------------------------------ Setup cell dependencies break marimo's execution model because: - The setup cell must run first to initialize the notebook - Dependencies on other cells would create impossible execution order - It violates the setup cell's purpose as initialization code This is a breaking error because it makes the notebook non-executable. Examples[¶](#examples "Permanent link") --------------------------------------- **Problematic:** `[](#__codelineno-0-1)# Setup cell [](#__codelineno-0-2)y = x + 1 # Error: setup depends on other cells [](#__codelineno-0-3)[](#__codelineno-0-4)# Cell 1 [](#__codelineno-0-5)x = 1` **Solution:** `[](#__codelineno-1-1)# Setup cell [](#__codelineno-1-2)y = 1 # Setup defines its own variables [](#__codelineno-1-3)[](#__codelineno-1-4)# Cell 1 [](#__codelineno-1-5)x = y + 1 # Other cells can use setup variables` References[¶](#references "Permanent link") ------------------------------------------- * [Setup References Guide](https://docs.marimo.io/guides/understanding_errors/setup/) * [Understanding Errors](https://docs.marimo.io/guides/understanding_errors/) Syntax error - marimo https://docs.marimo.io/guides/lint_rules/rules/invalid_syntax/ MB005: invalid-syntax[¶](#mb005-invalid-syntax "Permanent link") ---------------------------------------------------------------- 🚨 **Breaking** ❌ Not Fixable MB005: Cell contains code that throws a SyntaxError on compilation. What it does[¶](#what-it-does "Permanent link") ----------------------------------------------- Attempts to compile each cell using marimo's internal compiler and catches any SyntaxError exceptions that occur during the compilation process. Why is this bad?[¶](#why-is-this-bad "Permanent link") ------------------------------------------------------ Cells with syntax errors cannot be executed, making the notebook non-functional. SyntaxErrors prevent marimo from creating the dependency graph and running the reactive execution system, breaking the core functionality of the notebook. Examples[¶](#examples "Permanent link") --------------------------------------- **Problematic:** `[](#__codelineno-0-1)# Invalid indentation [](#__codelineno-0-2)if True: [](#__codelineno-0-3)print("Hello") # Missing indentation` **Problematic:** `[](#__codelineno-1-1)# Invalid syntax [](#__codelineno-1-2)x = 1 + # Missing operand` **Problematic:** `[](#__codelineno-2-1)# Mismatched brackets [](#__codelineno-2-2)my_list = [1, 2, 3 # Missing closing bracket` **Solution:** `[](#__codelineno-3-1)# Fix indentation [](#__codelineno-3-2)if True: [](#__codelineno-3-3) print("Hello") # Proper indentation` **Solution:** `[](#__codelineno-4-1)# Complete expressions [](#__codelineno-4-2)x = 1 + 2 # Complete arithmetic expression` **Solution:** `[](#__codelineno-5-1)# Match brackets [](#__codelineno-5-2)my_list = [1, 2, 3] # Proper closing bracket` References[¶](#references "Permanent link") ------------------------------------------- * [Understanding Errors](https://docs.marimo.io/guides/understanding_errors/) * [Python SyntaxError Documentation](https://docs.python.org/3/tutorial/errors.html#syntax-errors) Branch expression - marimo https://docs.marimo.io/guides/lint_rules/rules/branch_expression/ ⚠️ **Runtime** ❌ Not Fixable MR002: Branch statements with output expressions that won't be displayed. Why is this bad?[¶](#why-is-this-bad "Permanent link") ------------------------------------------------------ When output expressions are nested inside branches at the end of a cell: - The expressions execute but produce no visible output - Users expect to see the result (like mo.md(), string literals, etc.) - This can lead to confusion about whether code is running correctly - It violates the principle of least surprise This is a runtime issue because it causes unexpected behavior where the user's intended output is silently ignored. Examples[¶](#examples "Permanent link") --------------------------------------- **Problematic:** `[](#__codelineno-0-1)if condition: [](#__codelineno-0-2) mo.md("Result A") # Won't be displayed [](#__codelineno-0-3)else: [](#__codelineno-0-4) mo.md("Result B") # Won't be displayed` **Problematic:** `[](#__codelineno-1-1)match value: [](#__codelineno-1-2) case 1: [](#__codelineno-1-3) "Too short" # Won't be displayed [](#__codelineno-1-4) case _: [](#__codelineno-1-5) value # Won't be displayed` **Not flagged:** `[](#__codelineno-2-1)if condition: [](#__codelineno-2-2) print("Debug message") # Function calls` **Solution:** `[](#__codelineno-3-1)# Assign to a variable that marimo will display [](#__codelineno-3-2)result = mo.md("Result A") if condition else mo.md("Result B") [](#__codelineno-3-3)result` **Solution:** `[](#__codelineno-4-1)# Create a default variable for response. [](#__codelineno-4-2)result = None [](#__codelineno-4-3)if condition: [](#__codelineno-4-4) result = expr [](#__codelineno-4-5)else: [](#__codelineno-4-6) result = other [](#__codelineno-4-7)result` **Alternative Solution (if no output intended):** `[](#__codelineno-5-1)# Use a dummy variable to indicate intentional suppression [](#__codelineno-5-2)if condition: [](#__codelineno-5-3) _ = expr [](#__codelineno-5-4)else: [](#__codelineno-5-5) _ = other` References[¶](#references "Permanent link") ------------------------------------------- * [Understanding Errors](https://docs.marimo.io/guides/understanding_errors/) * [Reactivity](https://docs.marimo.io/guides/reactivity/) Self Import - marimo https://docs.marimo.io/guides/lint_rules/rules/self_import/ MR001: self-import[¶](#mr001-self-import "Permanent link") ---------------------------------------------------------- ⚠️ **Runtime** ❌ Not Fixable MR001: Importing a module with the same name as the file. What it does[¶](#what-it-does "Permanent link") ----------------------------------------------- Analyzes import statements in each cell to detect cases where the imported module name matches the current file's name (without the .py extension). Why is this bad?[¶](#why-is-this-bad "Permanent link") ------------------------------------------------------ Importing a module with the same name as the file causes several issues: - Python may attempt to import the current file instead of the intended module - This can lead to circular import errors or unexpected behavior - It makes the code confusing and hard to debug - It can prevent the notebook from running correctly This is a runtime issue because it can cause import confusion and unexpected behavior. Examples[¶](#examples "Permanent link") --------------------------------------- **Problematic (in a file named `requests.py`):** `[](#__codelineno-0-1)import requests # Error: conflicts with file name` **Problematic (in a file named `math.py`):** `[](#__codelineno-1-1)from math import sqrt # Error: conflicts with file name` **Solution:** `[](#__codelineno-2-1)# Rename the file to something else, like my_requests.py [](#__codelineno-2-2)import requests # Now this works correctly` **Alternative Solution:** `[](#__codelineno-3-1)# Use a different approach that doesn't conflict [](#__codelineno-3-2)import urllib.request # Use alternative library` References[¶](#references "Permanent link") ------------------------------------------- * [Understanding Errors](https://docs.marimo.io/guides/understanding_errors/) * [Python Import System](https://docs.python.org/3/reference/import.html) General formatting - marimo https://docs.marimo.io/guides/lint_rules/rules/general_formatting/ ✨ **Formatting** 🛠️ Fixable MF001: General formatting issues with the notebook format. What it does[¶](#what-it-does "Permanent link") ----------------------------------------------- Examines the notebook serialization for structural violations such as: - Missing or incorrect marimo import statements - Improperly formatted cell definitions - Missing app initialization code - Incorrect file generation metadata Why is this bad?[¶](#why-is-this-bad "Permanent link") ------------------------------------------------------ Format violations can prevent marimo from properly loading or executing notebooks. While these don't affect the Python code logic, formatting errors mark a deviation in the expected script structure, which can lead to unexpected behavior when run as a script, or when loading the notebook. Examples[¶](#examples "Permanent link") --------------------------------------- **Problematic:** `[](#__codelineno-0-1)# Missing marimo import [](#__codelineno-0-2)@app.cell [](#__codelineno-0-3)def __(): [](#__codelineno-0-4) return [](#__codelineno-0-5) [](#__codelineno-0-6)[](#__codelineno-0-7)if __name__ == "__main__": [](#__codelineno-0-8) app.run()` **Solution:** `[](#__codelineno-1-1)import marimo [](#__codelineno-1-2)[](#__codelineno-1-3)__generated_with = "0.1.0" [](#__codelineno-1-4)app = marimo.App() [](#__codelineno-1-5) [](#__codelineno-1-6)[](#__codelineno-1-7)@app.cell [](#__codelineno-1-8)def __(): [](#__codelineno-1-9) return [](#__codelineno-1-10) [](#__codelineno-1-11)[](#__codelineno-1-12)if __name__ == "__main__": [](#__codelineno-1-13) app.run()` **Note:** Most format issues are automatically fixable with `marimo check --fix`. References[¶](#references "Permanent link") ------------------------------------------- * [Understanding Errors](https://docs.marimo.io/guides/understanding_errors/) * [File Format Documentation](https://docs.marimo.io/guides/coming_from/jupyter/#marimo-file-format) Parse stdout - marimo https://docs.marimo.io/guides/lint_rules/rules/parse_stdout/ MF002: parse-stdout[¶](#mf002-parse-stdout "Permanent link") ------------------------------------------------------------ ✨ **Formatting** ❌ Not Fixable MF002: Parse captured stdout during notebook loading. What it does[¶](#what-it-does "Permanent link") ----------------------------------------------- Captures and parses stdout output during notebook loading, looking for structured warning messages that include file and line number references. Creates diagnostics from any warnings or messages found. Why is this bad?[¶](#why-is-this-bad "Permanent link") ------------------------------------------------------ While stdout output doesn't prevent execution, it often indicates: - Deprecation warnings from imported libraries - Configuration issues - Potential compatibility problems - Code that produces unexpected side effects during import Examples[¶](#examples "Permanent link") --------------------------------------- **Captured stdout:** `[](#__codelineno-0-1)notebook.py:15: DeprecationWarning: 'imp' module is deprecated` **Result:** Creates a diagnostic pointing to line 15 with the deprecation warning. References[¶](#references "Permanent link") ------------------------------------------- * [Understanding Errors](https://docs.marimo.io/guides/understanding_errors/) Parse stderr - marimo https://docs.marimo.io/guides/lint_rules/rules/parse_stderr/ MF003: parse-stderr[¶](#mf003-parse-stderr "Permanent link") ------------------------------------------------------------ ✨ **Formatting** ❌ Not Fixable MF003: Parse captured stderr during notebook loading. What it does[¶](#what-it-does "Permanent link") ----------------------------------------------- Captures stderr output during notebook loading and creates diagnostics from any error messages or warnings. This helps identify potential issues that don't prevent parsing but may affect runtime behavior. Why is this bad?[¶](#why-is-this-bad "Permanent link") ------------------------------------------------------ Stderr output during parsing often indicates: - Syntax warnings (like invalid escape sequences) - Import warnings or errors - Deprecation notices from libraries - Configuration issues that might affect execution While these don't break the notebook, they can lead to unexpected behavior or indicate code that needs updating. Examples[¶](#examples "Permanent link") --------------------------------------- **Captured stderr:** `[](#__codelineno-0-1)notebook.py:68: SyntaxWarning: invalid escape sequence '\l'` **Result:** Creates a diagnostic pointing to line 68 about the invalid escape sequence. **Common issues:** - Raw strings needed: `r"\path\to\file"` instead of `"\path\to\file"` - Deprecated library usage - Missing import dependencies References[¶](#references "Permanent link") ------------------------------------------- * [Understanding Errors](https://docs.marimo.io/guides/understanding_errors/) * [Python Warning Categories](https://docs.python.org/3/library/warnings.html#warning-categories) Empty cells - marimo https://docs.marimo.io/guides/lint_rules/rules/empty_cells/ MF004: empty-cells[¶](#mf004-empty-cells "Permanent link") ---------------------------------------------------------- ✨ **Formatting** ⚠️ Unsafe Fixable MF004: Empty cells that can be safely removed. What it does[¶](#what-it-does "Permanent link") ----------------------------------------------- Detects cells that contain only: - Whitespace characters (spaces, tabs, newlines) - Comments (lines starting with #) - Pass statements (`pass`) - Any combination of the above Why is this bad?[¶](#why-is-this-bad "Permanent link") ------------------------------------------------------ Empty cells can: - Create clutter in notebook structure - Add unnecessary complexity to the execution graph - Make notebooks harder to read and maintain - Increase file size without adding value While not functionally breaking, removing empty cells improves code clarity and reduces visual noise. Examples[¶](#examples "Permanent link") --------------------------------------- **Problematic:** `[](#__codelineno-0-1)# Cell 1: Only whitespace` **Problematic:** `[](#__codelineno-1-1)# Cell 2: Only comments [](#__codelineno-1-2)# This is just a comment [](#__codelineno-1-3)# Nothing else here` **Problematic:** `[](#__codelineno-2-1)# Cell 3: Only pass statement [](#__codelineno-2-2)pass` **Problematic:** `[](#__codelineno-3-1)# Cell 4: Mix of comments, whitespace, and pass [](#__codelineno-3-2)# Some comment [](#__codelineno-3-3)[](#__codelineno-3-4)pass [](#__codelineno-3-5)# Another comment` **Note:** This fix requires `--unsafe-fixes` because removing cells changes the notebook structure, and potentially removes user-intended content. References[¶](#references "Permanent link") ------------------------------------------- * [Understanding Errors](https://docs.marimo.io/guides/understanding_errors/) * [Best Practices](https://docs.marimo.io/guides/best_practices/) Markdown Dedent - marimo https://docs.marimo.io/guides/lint_rules/rules/markdown_dedent/ MF007: markdown-indentation[¶](#mf007-markdown-indentation "Permanent link") ---------------------------------------------------------------------------- ✨ **Formatting** 🛠️ Fixable MF007: Markdown strings in `mo.md()` should be dedented. What it does[¶](#what-it-does "Permanent link") ----------------------------------------------- Checks cells containing `mo.md()` calls to see if the markdown string content has unnecessary leading whitespace that should be removed. Why is this bad?[¶](#why-is-this-bad "Permanent link") ------------------------------------------------------ Indented markdown strings: * Are harder to read when viewing the source code * Produce larger diffs when making changes * Don't match the standard marimo formatting style * Can be confusing when the indentation doesn't reflect the markdown structure Examples[¶](#examples "Permanent link") --------------------------------------- **Problematic:** `[](#__codelineno-0-1)mo.md( [](#__codelineno-0-2) r""" [](#__codelineno-0-3) # Title [](#__codelineno-0-4) [](#__codelineno-0-5) Some content here. [](#__codelineno-0-6) """ [](#__codelineno-0-7))` **Solution:** `[](#__codelineno-1-1)mo.md(r""" [](#__codelineno-1-2)# Title [](#__codelineno-1-3)[](#__codelineno-1-4)Some content here. [](#__codelineno-1-5)""")` **Note:** This fix is automatically applied with `marimo check --fix`. References[¶](#references "Permanent link") ------------------------------------------- * [Understanding Errors](https://docs.marimo.io/guides/understanding_errors/) * [Best Practices](https://docs.marimo.io/guides/best_practices/) Markdown Indentation - marimo https://docs.marimo.io/guides/lint_rules/rules/markdown_indentation/ ✨ **Formatting** 🛠️ Fixable MF007: Markdown strings in `mo.md()` should be properly indented. What it does[¶](#what-it-does "Permanent link") ----------------------------------------------- Checks cells containing `mo.md()` calls to see if the markdown string content has unnecessary leading whitespace that should be removed. Why is this bad?[¶](#why-is-this-bad "Permanent link") ------------------------------------------------------ Indented markdown strings: - Are harder to read when viewing the source code - Produce larger diffs when making changes - Don't match the standard marimo formatting style - Can be confusing when the indentation doesn't reflect the markdown structure Examples[¶](#examples "Permanent link") --------------------------------------- **Problematic:** `[](#__codelineno-0-1)mo.md( [](#__codelineno-0-2) r""" [](#__codelineno-0-3) # Title [](#__codelineno-0-4) [](#__codelineno-0-5) Some content here. [](#__codelineno-0-6) """ [](#__codelineno-0-7))` **Solution:** `[](#__codelineno-1-1)mo.md(r""" [](#__codelineno-1-2)# Title [](#__codelineno-1-3)[](#__codelineno-1-4)Some content here. [](#__codelineno-1-5)""")` **Note:** This fix is automatically applied with `marimo check --fix`. References[¶](#references "Permanent link") ------------------------------------------- * [Understanding Errors](https://docs.marimo.io/guides/understanding_errors/) * [Best Practices](https://docs.marimo.io/guides/best_practices/) SQL parse error - marimo https://docs.marimo.io/guides/lint_rules/rules/sql_parse_error/ ✨ **Formatting** ❌ Not Fixable MF005: SQL parsing errors during dependency analysis. What it does[¶](#what-it-does "Permanent link") ----------------------------------------------- Captures SQL parsing error logs and creates diagnostics pointing to problematic SQL statements in cells. Why is this bad?[¶](#why-is-this-bad "Permanent link") ------------------------------------------------------ SQL parsing failures can lead to: - Incorrect dependency analysis for SQL-using cells - Missing dataframe references in dependency graph - Reduced effectiveness of reactive execution - Potential runtime errors when SQL is executed Examples[¶](#examples "Permanent link") --------------------------------------- **Triggered by:** - Invalid SQL syntax in cell code - Unsupported SQL dialects or extensions - Complex SQL that exceeds parser capabilities References[¶](#references "Permanent link") ------------------------------------------- * [Understanding Errors](https://docs.marimo.io/guides/understanding_errors/) * [SQL Support](https://docs.marimo.io/guides/sql/) Misc parse log - marimo https://docs.marimo.io/guides/lint_rules/rules/misc_log_capture/ MF006: misc-log-capture[¶](#mf006-misc-log-capture "Permanent link") -------------------------------------------------------------------- ✨ **Formatting** ❌ Not Fixable MF006: Miscellaneous log messages during processing. What it does[¶](#what-it-does "Permanent link") ----------------------------------------------- Captures warning and error level log messages that aren't handled by other specific log rules and creates diagnostics to surface them. Why is this bad?[¶](#why-is-this-bad "Permanent link") ------------------------------------------------------ Unhandled log messages may indicate: - Unexpected issues during notebook processing - Configuration problems - Library warnings that affect execution - Performance or resource issues Examples[¶](#examples "Permanent link") --------------------------------------- **Triggered by:** - General warnings from imported libraries - Configuration issues - Unexpected errors during processing References[¶](#references "Permanent link") ------------------------------------------- * [Understanding Errors](https://docs.marimo.io/guides/understanding_errors/) Testing notebooks - marimo https://docs.marimo.io/guides/testing/ Because marimo notebooks are stored as Python, test them like any other Python program. | Guide | Description | | --- | --- | | [pytest](https://docs.marimo.io/guides/testing/pytest/) | Include unit tests in notebooks, or implement entire tests as notebooks | | [doctest](https://docs.marimo.io/guides/testing/doctest/) | Test code snippets in docstrings using doctest | Troubleshooting - marimo https://docs.marimo.io/guides/troubleshooting/ marimo understands the relationships between cells based on the variables they define and reference. When things don't work as expected, marimo provides [several tools](https://docs.marimo.io/guides/editor_features/dataflow/) to help you understand both marimo's interpretation of your notebook and debug issues. This guide covers common issues and unexpected behaviors you might encounter, along with ways to debug and resolve them. For interactive debugging techniques, see our [debugging guide](https://docs.marimo.io/guides/debugging/). If your issue isn't covered here, try checking our [FAQ](https://docs.marimo.io/faq/). Why aren't my cells running?[¶](#why-arent-my-cells-running "Permanent link") ----------------------------------------------------------------------------- If you're expecting cells to run in response to changes in other cells, but they're not, consider the following: ### Check for mutations[¶](#check-for-mutations "Permanent link") marimo doesn't track mutations to objects. If you're modifying an object in one cell and expecting another cell to react, this won't work as expected. Instead of mutating objects across cells, try creating new objects or performing all mutations within the same cell. [Read more about reactivity](https://docs.marimo.io/guides/reactivity/). ### Verify cell connections[¶](#verify-cell-connections "Permanent link") Use marimo's [dataflow tools](https://docs.marimo.io/guides/editor_features/dataflow/) to check if your cells are actually connected as you expect. Toggle the [minimap](https://docs.marimo.io/guides/editor_features/dataflow/#minimap) to see the current cell's connections. You should see connections to cells you expect as inputs on the left and outgoing connections to other cells on the right. Here, the cell defining `f` depends on the two cells above and connects to the one below with `print(f)`. Alternatively, you can open the [dependency graph](https://docs.marimo.io/guides/editor_features/dataflow/#graph-view) or [variables panel](https://docs.marimo.io/guides/editor_features/dataflow/#variables-explorer) in the sidebar. Dependency graph showing cell connections. If connections are missing, review your variable usage to ensure cells are properly referencing each other. Why is my cell running unexpectedly?[¶](#why-is-my-cell-running-unexpectedly "Permanent link") ---------------------------------------------------------------------------------------------- If a cell is running more often than you anticipate: ### Check cell dependencies[¶](#check-cell-dependencies "Permanent link") Use marimo's [dataflow tools](https://docs.marimo.io/guides/editor_features/dataflow/) to see what's triggering your cell: 1. Toggle the [minimap](https://docs.marimo.io/guides/editor_features/dataflow/#minimap) (see [above](#verify-cell-connections)) - cells on the left are inputs that trigger your cell when they run. 2. Check the [variables explorer](https://docs.marimo.io/guides/editor_features/dataflow/#variables-explorer) to see which variables your cell uses and where they're defined. 3. You might find unexpected dependencies that are causing the cell to run. ### Understand global vs local variables vs functions args[¶](#understand-global-vs-local-variables-vs-functions-args "Permanent link") Ensure you're not inadvertently using a global variables when intending to use a local variable or function argument: 1. Check for any variables used in your cell that aren't defined within it. 2. Consider using local variables (prefixed with `_`) for values that shouldn't be consumed by other cells. Why is my UI element's value being reset?[¶](#why-is-my-ui-elements-value-being-reset "Permanent link") ------------------------------------------------------------------------------------------------------- If a UI element's value keeps resetting: ### Check that cell defining the UI element isn't rerunning[¶](#check-that-cell-defining-the-ui-element-isnt-rerunning "Permanent link") If the cell defining the UI element reruns, it will reset the element's value to its initial `value` argument. You may be able to avoid this by splitting the UI element definition into a separate cell. ### Use state for persistence[¶](#use-state-for-persistence "Permanent link") If you need to maintain UI element values across cell runs, consider using `mo.state`: `[](#__codelineno-0-1)# Declare state in a separate cell [](#__codelineno-0-2)get_value, set_value = mo.state(initial_value)` `[](#__codelineno-1-1)element = mo.ui.slider(0, 10, value=get_value(), on_change=set_value)` This way, the value persists even if the cell defining the element reruns. How can I force one cell to run after another?[¶](#how-can-i-force-one-cell-to-run-after-another "Permanent link") ------------------------------------------------------------------------------------------------------------------ If you need to ensure a specific execution order: ### Use explicit dependencies[¶](#use-explicit-dependencies "Permanent link") Create an explicit dependency by using a variable from the first cell in the second: `[](#__codelineno-2-1)# Cell 1 [](#__codelineno-2-2)result = some_computation()` `[](#__codelineno-3-1)# Cell 2 [](#__codelineno-3-2)_ = result # This creates a dependency on Cell 1 [](#__codelineno-3-3)further_computation()` ### Consider refactoring[¶](#consider-refactoring "Permanent link") If you find yourself needing to force execution order often, it might be a sign that your notebook structure could be improved: 1. Try to organize your cells so that natural data flow creates the desired order. 2. Consider combining related operations into single cells where appropriate. General debugging tips[¶](#general-debugging-tips "Permanent link") ------------------------------------------------------------------- ### Check for common issues with the linter[¶](#check-for-common-issues-with-the-linter "Permanent link") Before diving into manual debugging, try running marimo's built-in linter to catch common issues: `[](#__codelineno-4-1)marimo check my_notebook.py` The linter can identify problems like: - Multiple variable definitions across cells - Circular dependencies between cells - Unparsable code that prevents execution - Other code quality issues See the [Lint Rules](https://docs.marimo.io/guides/lint_rules/) guide for a complete list of checks. ### Understanding dependencies[¶](#understanding-dependencies "Permanent link") * Use the Variables Panel to inspect variable values and see where they're defined and used. * Add print statements or use `mo.md()` to output debug information in cell outputs. * Temporarily disable cells to isolate issues. * Use the "Lazy" runtime configuration to see which cells are being marked as stale without automatically running them. Remember, marimo's reactivity is based on global variable definitions and references, and mutations to objects aren't tracked. Keeping this in mind can help you understand and debug unexpected behaviors in your notebooks. Patches made by marimo[¶](#patches-made-by-marimo "Permanent link") ------------------------------------------------------------------- ### Why can't I import a local library?[¶](#why-cant-i-import-a-local-library "Permanent link") When using `marimo edit path/to/notebook.py` or `marimo run path/to/notebook.py`, marimo sets `sys.path` to match what you would get with `python path/to/notebook.py`. In particular, setting `sys.path[0]` to the notebook directory: `[](#__codelineno-5-1)sys.path[0] == 'path/to/'` You can add entries to `sys.path` in your pyproject.toml [runtime configuration](https://docs.marimo.io/guides/configuration/runtime_configuration/). ### Other patches[¶](#other-patches "Permanent link") When running as a notebook, marimo makes the following changes to variables: * marimo patches `pdb.Pdb` with a custom class to enable interactive debugging with the `breakpoint()` function * marimo patches `sys.argv` when running as a notebook to match what you would see when [running as a script](https://docs.marimo.io/guides/scripts/). * local variables currently have their names mangled, meaning source code introspection that uses local variables may not work; this behavior may change in the future. Why is the notebook returning 404s on the web assets?[¶](#why-is-the-notebook-returning-404s-on-the-web-assets "Permanent link") -------------------------------------------------------------------------------------------------------------------------------- If you're seeing 404 errors for web assets like JS or CSS files, it may be due to symlink settings or proxy settings. ### Check symlink settings[¶](#check-symlink-settings "Permanent link") If you are using `bazel` or `uv`'s [**link-mode: symlink**](https://docs.astral.sh/uv/reference/settings/#link-mode), you may need to adjust your symlink settings to ensure that web assets are correctly found. By default marimo does not follow symlinks, so you may need to turn this setting on. Locate your `marimo.toml` configuration file with `marimo config show`, and edit the `follow_symlink` flag: marimo.toml `[](#__codelineno-6-1)[server] [](#__codelineno-6-2)follow_symlink = true` ### Check proxy settings[¶](#check-proxy-settings "Permanent link") If you are using a proxy server, you need to include the `--proxy` flag when running marimo. The proxy will default to port 80 if no port is specified. For example, if your proxy is `example.com` and it uses port 8080, you would run: `[](#__codelineno-7-1)marimo edit --proxy example.com:8080 [](#__codelineno-7-2)# or [](#__codelineno-7-3)marimo run --proxy example.com:8080` ### Reading the logs[¶](#reading-the-logs "Permanent link") marimo will output logs to `$XDG_CACHE_HOME/marimo/logs/*`. To view the logs, run: `[](#__codelineno-8-1)cat $XDG_CACHE_HOME/marimo/logs/github-copilot-lsp.log` Available logs are: * `github-copilot-lsp.log` * `pylsp.log` pytest - marimo https://docs.marimo.io/guides/testing/pytest/ Testing with pytest[¶](#testing-with-pytest "Permanent link") ------------------------------------------------------------- Testing in notebook[¶](#testing-in-notebook "Permanent link") ------------------------------------------------------------- By default, marimo discovers and executes tests inside your notebook. When the optional `pytest` dependency is present, marimo runs `pytest` on cells that consist exclusively of test code - i.e. functions whose names start with `test_`, classes whose names start with `Test`, or functions decorated with `@pytest.fixture`. If a cell mixes in anything else (helper functions, constants, variables, imports, etc.), that cell is skipped by the test runner (we recommend you move helpers to another cell). For example, Reactive tests can be disabled You can disable this behavior with the `runtime.reactive_test` option in the configuration file. Testing at the command-line[¶](#testing-at-the-command-line "Permanent link") ----------------------------------------------------------------------------- Since marimo notebooks are Python programs, you can test them using [`pytest`](https://docs.pytest.org/en/stable/), a popular testing framework for Python. For example, runs and tests all notebook cells whose names start with `test_`, or cells that contain only `test_` functions and `Test` classes (just like in notebook tests). Naming cells Name a cell by giving its function a name in the notebook file, or using the cell action menu in the notebook editor. Use marimo notebooks just like normal pytest tests Include test notebooks (notebooks whose names start with `test_`) in your standard test suite, and `pytest` will discover them automatically. In addition, you can write self-contained notebooks that contain their own unit tests, and run `pytest` on them directly (`pytest my_notebook.py`). Example[¶](#example "Permanent link") ------------------------------------- Running `pytest` on `[](#__codelineno-2-1)# content of test_notebook.py [](#__codelineno-2-2)import marimo [](#__codelineno-2-3)[](#__codelineno-2-4)__generated_with = "0.10.6" [](#__codelineno-2-5)app = marimo.App() [](#__codelineno-2-6) [](#__codelineno-2-7)[](#__codelineno-2-8)@app.cell [](#__codelineno-2-9)def _(): [](#__codelineno-2-10) def inc(x): [](#__codelineno-2-11) return x + 1 [](#__codelineno-2-12) return (inc,) [](#__codelineno-2-13) [](#__codelineno-2-14)[](#__codelineno-2-15)@app.cell [](#__codelineno-2-16)def test_fails(inc): [](#__codelineno-2-17) assert inc(3) == 5, "This test fails" [](#__codelineno-2-18) [](#__codelineno-2-19)[](#__codelineno-2-20)@app.cell [](#__codelineno-2-21)def test_sanity(inc): [](#__codelineno-2-22) assert inc(3) == 4, "This test passes" [](#__codelineno-2-23)[](#__codelineno-2-24)@app.cell [](#__codelineno-2-25)def collection_of_tests(inc, pytest): [](#__codelineno-2-26) @pytest.mark.parametrize(("x", "y"), [(3, 4), (4, 5)]) [](#__codelineno-2-27) def test_answer(x, y): [](#__codelineno-2-28) assert inc(x) == y, "These tests should pass." [](#__codelineno-2-29)[](#__codelineno-2-30)@app.cell [](#__codelineno-2-31)def imports(): [](#__codelineno-2-32) import pytest [](#__codelineno-2-33) return pytest` prints `[](#__codelineno-3-1)============================= test session starts ============================== [](#__codelineno-3-2)platform linux -- Python 3.12.9, pytest-8.3.5, pluggy-1.5.0 [](#__codelineno-3-3)rootdir: /notebooks [](#__codelineno-3-4)configfile: pyproject.toml [](#__codelineno-3-5)collected 4 items [](#__codelineno-3-6)[](#__codelineno-3-7)test_notebook.py::test_fails FAILED [ 25%] [](#__codelineno-3-8)test_notebook.py::test_sanity PASSED [ 50%] [](#__codelineno-3-9)test_notebook.py::MarimoTestBlock_0::test_parameterized[3-4] PASSED [ 75%] [](#__codelineno-3-10)test_notebook.py::MarimoTestBlock_0::test_parameterized[4-5] PASSED [100%] [](#__codelineno-3-11)[](#__codelineno-3-12)=================================== FAILURES =================================== [](#__codelineno-3-13)__________________________________ test_fails __________________________________ [](#__codelineno-3-14) [](#__codelineno-3-15) # content of test_notebook.py [](#__codelineno-3-16) import marimo [](#__codelineno-3-17) [](#__codelineno-3-18) __generated_with = "0.10.6" [](#__codelineno-3-19) app = marimo.App() [](#__codelineno-3-20) [](#__codelineno-3-21) [](#__codelineno-3-22) @app.cell [](#__codelineno-3-23) def _(): [](#__codelineno-3-24) def inc(x): [](#__codelineno-3-25) return x + 1 [](#__codelineno-3-26) return (inc,) [](#__codelineno-3-27) [](#__codelineno-3-28) [](#__codelineno-3-29) @app.cell [](#__codelineno-3-30) def test_fails(inc): [](#__codelineno-3-31)> assert inc(3) == 5, "This test fails" [](#__codelineno-3-32)E AssertionError: This test fails [](#__codelineno-3-33)E assert 4 == 5 [](#__codelineno-3-34)E + where 4 = (3) [](#__codelineno-3-35)[](#__codelineno-3-36)test_notebook.py:17: AssertionError [](#__codelineno-3-37)=========================== short test summary info ============================ [](#__codelineno-3-38)FAILED test_notebook.py::test_fails - AssertionError: This test fails [](#__codelineno-3-39)========================= 1 failed, 3 passed in 0.82s ==========================` Using Pytest Fixtures[¶](#using-pytest-fixtures "Permanent link") ----------------------------------------------------------------- marimo supports pytest fixtures, with one limitation: fixtures defined in one cell cannot be used in another cell, unless the fixtures were defined in the setup cell. For this reason, we recommend defining (or importing) fixtures in your notebook's setup cell, or defining fixtures in a pytest `conftest.py` file. ### Examples[¶](#examples "Permanent link") **Fixtures defined in the setup cell**: `[](#__codelineno-4-1)# test_notebook.py [](#__codelineno-4-2)import marimo [](#__codelineno-4-3)app = marimo.App() [](#__codelineno-4-4)[](#__codelineno-4-5)with app.setup: [](#__codelineno-4-6) from fixtures import db_connection, sample_data [](#__codelineno-4-7)[](#__codelineno-4-8)@app.cell [](#__codelineno-4-9)def _(sample_data): [](#__codelineno-4-10) def test_data_loaded(sample_data): [](#__codelineno-4-11) assert len(sample_data) > 0` **Fixtures in the same cell as tests**: `[](#__codelineno-5-1)@app.cell [](#__codelineno-5-2)def _(): [](#__codelineno-5-3) import pytest [](#__codelineno-5-4) return pytest [](#__codelineno-5-5) [](#__codelineno-5-6)[](#__codelineno-5-7)@app.cell [](#__codelineno-5-8)def _(pytest): [](#__codelineno-5-9) @pytest.fixture [](#__codelineno-5-10) def temp_file(): [](#__codelineno-5-11) import tempfile [](#__codelineno-5-12) with tempfile.NamedTemporaryFile() as f: [](#__codelineno-5-13) yield f [](#__codelineno-5-14) [](#__codelineno-5-15) def test_writes_to_file(temp_file): [](#__codelineno-5-16) temp_file.write(b"hello") [](#__codelineno-5-17) temp_file.seek(0) [](#__codelineno-5-18) assert temp_file.read() == b"hello"` **Class fixtures**: `[](#__codelineno-6-1)@app.cell [](#__codelineno-6-2)def _(): [](#__codelineno-6-3) import pytest [](#__codelineno-6-4) return pytest [](#__codelineno-6-5) [](#__codelineno-6-6)[](#__codelineno-6-7)@app.cell [](#__codelineno-6-8)def _(pytest): [](#__codelineno-6-9) class TestDatabase: [](#__codelineno-6-10) @pytest.fixture(scope="class") [](#__codelineno-6-11) def connection(self): [](#__codelineno-6-12) return create_connection() [](#__codelineno-6-13) [](#__codelineno-6-14) def test_query(self, connection): [](#__codelineno-6-15) result = connection.query("SELECT 1") [](#__codelineno-6-16) assert result == 1` **`conftest.py` fixtures** work as expected - pytest discovers them automatically. Fixture Limitations Fixtures defined in one cell **cannot** be used by tests in a different cell. This is because pytest collects tests **statically** by parsing the notebook file without executing it. During collection, pytest can see module-level fixtures (from `conftest.py` or imported modules) and fixtures defined in the same scope as the test, but it cannot see fixtures defined in other cells. **Why?** Running the entire notebook just for fixture discovery would be expensive, and static analysis cannot determine which fixtures will be available after cell execution since cell order is determined at runtime by marimo's dependency graph. doctest - marimo https://docs.marimo.io/guides/testing/doctest/ Tip: paste this code into an empty cell, and the marimo editor will create cells for you `import marimo __generated_with = "0.19.7" app = marimo.App(width="medium") @app.cell def _(): import marimo as mo return (mo,) @app.function def euclid_mcd(a: int, b: int) -> int: """Return the MCD between positive a, b. >>> euclid_mcd(42, 24) 6 >>> euclid_mcd(24, 42) 6 >>> euclid_mcd(42, 42) 42 """ assert a > 0 assert b > 0 if a < b: a, b = b, a if (a != b): r = a - b return euclid_mcd(b, r) return a @app.cell def _(mo): # Include a reference to each function to test euclid_mcd import doctest failures, success = doctest.testmod(verbose=True) mo.md(f"Success: {success}, Failures: {failures}") return if __name__ == "__main__": app.run()` Dangerously set state - marimo https://docs.marimo.io/guides/state/ Reactive state[¶](#reactive-state "Permanent link") --------------------------------------------------- Advanced topic! This guide covers reactive state (`mo.state`), an advanced topic. **You likely don't need `mo.state`**. UI elements already have built-in state, their associated value, which you can access with their `value` attribute. For example, `mo.ui.slider()` has a value that is its current position on an interval, while `mo.ui.button()` has a value that can be configured to count the number of times it has been clicked, or to toggle between `True` and `False`. Additionally, interacting with UI elements bound to global variables [automatically executes cells](https://docs.marimo.io/guides/interactivity/) that reference those variables, letting you react to changes by just reading their `value` attributes. **This functional paradigm is the preferred way of reacting to UI interactions in marimo.** **Chances are, the reactive execution built into UI elements will suffice.** (For example, [you don't need reactive state to handle a button click](https://docs.marimo.io/recipes/#working-with-buttons).) That said, here are some signs you might need `mo.state`: * you need to maintain historical state related to a UI element that can't be computed from its built-in `value` (_e.g._, all values the user has ever input into a form) * you need to synchronize two different UI elements (_e.g._, so that interacting with either one controls the other) * you need to introduce cycles across cells **In over 99% of cases, you don't need and shouldn't use `mo.state`.** This feature can introduce hard-to-find bugs. You can build powerful, interactive notebooks and apps using just `mo.ui` and reactivity. But sometimes, you might want interactions to mutate state: * You're building a checklist, and you want to maintain a list of action items, even as you add and remove some items. A proof-of-concept TODO list made using state. * You want to tie two different UI elements so that updating **either** one updates the other. Use state to tie two elements together in a cycle. Use reactive execution for uni-directional flow If you just want the value of a single element to update another element, then **you shouldn't use `mo.state`**. Instead, use marimo's built-in reactive execution --- see the [interactivity guide](https://docs.marimo.io/guides/interactivity/). For cases like these, marimo provides the function [`mo.state()`](https://docs.marimo.io/api/state/), which creates a state object and returns a getter and setter function. When you call the setter function in one cell, all other cells that reference the getter function **via a global variable** are automatically run (similar to UI elements). State and UI elements are similar State is analogous to UI elements. When you interact with a UI element, all cells that reference that element via a global variable run automatically with the new value. In the same way, when you update state via the setter, all other cells that reference the getter via a global variable run automatically with the new value. [`mo.state()`](https://docs.marimo.io/api/state/) takes an initial state value as its argument, creates a state object, and returns * a getter function for reading the state * a setter function for updating the state For exaxmple, `[](#__codelineno-0-1)get_counter, set_counter = mo.state(0)` Assign state to global variables! When using `mo.state()`, **you must assign the state getter to a global variable**. This is similar to UI elements work. Reading state[¶](#reading-state "Permanent link") ------------------------------------------------- Access the state's latest value via the getter: Updating state[¶](#updating-state "Permanent link") --------------------------------------------------- You can update a state's value by calling its setter function with a new value. For example, To update the state based on its current value, pass a function that takes the current state value as an argument and returns a new value `[](#__codelineno-3-1)set_counter(lambda count: count + 1)` A single rule determines what happens next: State reactivity rule When a state setter function is called in one cell, marimo automatically runs all _other_ cells that reference any **global** variables assigned to the state getter. This rule has some important aspects: 1. Only cells that read the state getter via a global variable will be run. 2. The cell that called the setter won't be re-run, even if it references the getter. This restriction helps prevent against bugs that could otherwise arise. To lift this restriction, and allow the caller cell to be re-run, create your state with `mo.state(value, allow_self_loops=True)`. Notice how similar this rule is to the reactivity rule for UI element interactions. Using state with UI elements[¶](#using-state-with-ui-elements "Permanent link") ------------------------------------------------------------------------------- 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. Use state sparingly You can get far using just `mo.ui`, without state, because marimo automatically runs cells that reference UI elements on interaction (see the [interactivity guide](https://docs.marimo.io/guides/interactivity/)). Only use `on_change` callbacks as a last resort! ### Example: counter[¶](#example-counter "Permanent link") The next few cells implement a counter controlled by two buttons. This particular example could be implemented without state (try it!), but the implementation using state is simpler. `[](#__codelineno-5-1)get_counter, set_counter = mo.state(0) [](#__codelineno-5-2)[](#__codelineno-5-3)increment = mo.ui.button( [](#__codelineno-5-4) label="increment", [](#__codelineno-5-5) on_change=lambda _: set_counter(lambda v: v + 1), [](#__codelineno-5-6)) [](#__codelineno-5-7)[](#__codelineno-5-8)decrement = mo.ui.button( [](#__codelineno-5-9) label="decrement", [](#__codelineno-5-10) on_change=lambda _: set_counter(lambda v: v - 1), [](#__codelineno-5-11)) [](#__codelineno-5-12)[](#__codelineno-5-13)mo.hstack([increment, decrement], justify="center")` `[](#__codelineno-6-1)mo.md( [](#__codelineno-6-2) f""" [](#__codelineno-6-3) The counter's current value is **{get_counter()}**! [](#__codelineno-6-4) [](#__codelineno-6-5) This cell runs automatically on button click, even though it [](#__codelineno-6-6) doesn't reference either button. [](#__codelineno-6-7) """ [](#__codelineno-6-8))` ### Example: tied elements[¶](#example-tied-elements "Permanent link") This example shows how to tie two different UI elements so that each one's value depends on the other. This is impossible to do without `mo.state`. `[](#__codelineno-8-1)get_x, set_x = mo.state(0)` `[](#__codelineno-9-1)x = mo.ui.slider( [](#__codelineno-9-2) 0, 10, value=get_x(), on_change=set_x, label="$x$:" [](#__codelineno-9-3))` `[](#__codelineno-10-1)x_plus_one = mo.ui.number( [](#__codelineno-10-2) 1, [](#__codelineno-10-3) 11, [](#__codelineno-10-4) value=get_x() + 1, [](#__codelineno-10-5) on_change=lambda v: set_x(v - 1), [](#__codelineno-10-6) label="$x + 1$:", [](#__codelineno-10-7))` Create tied UI elements in separate cells Notice that we created the slider and number elements in different cells. When tying elements, this is necessary, because calling a setter in a cell queues all _other_ cells reading the state to run, not including the one that just called the setter. Cycles at runtime You can use state to introduce cycles across cells at runtime. This lets you tie multiple UI elements together, for example. Just be careful not to introduce an infinite loop! marimo programs are statically parsed into directed acyclic graphs (DAGs) involving cells, and state doesn't change that. Think of state setters as hooking into the DAG: at runtime, when they're invoked (and only when they're invoked), they trigger additional computation. ### Example: todo list[¶](#example-todo-list "Permanent link") The next few cells use state to create a todo list. `[](#__codelineno-12-1)import marimo as mo [](#__codelineno-12-2)from dataclasses import dataclass` `[](#__codelineno-13-1)@dataclass [](#__codelineno-13-2)class Task: [](#__codelineno-13-3) name: str [](#__codelineno-13-4) done: bool = False [](#__codelineno-13-5) [](#__codelineno-13-6)[](#__codelineno-13-7)get_tasks, set_tasks = mo.state([]) [](#__codelineno-13-8)task_added, set_task_added = mo.state(False)` `[](#__codelineno-14-1)# Refresh the text box whenever a task is added [](#__codelineno-14-2)task_added [](#__codelineno-14-3)[](#__codelineno-14-4)task_entry_box = mo.ui.text(placeholder="a task ...")` `[](#__codelineno-15-1)def add_task(): [](#__codelineno-15-2) if task_entry_box.value: [](#__codelineno-15-3) set_tasks(lambda v: v + [Task(task_entry_box.value)]) [](#__codelineno-15-4) set_task_added(True) [](#__codelineno-15-5)[](#__codelineno-15-6)def clear_tasks(): [](#__codelineno-15-7) set_tasks(lambda v: [task for task in v if not task.done]) [](#__codelineno-15-8)[](#__codelineno-15-9)add_task_button = mo.ui.button( [](#__codelineno-15-10) label="add task", [](#__codelineno-15-11) on_change=lambda _: add_task(), [](#__codelineno-15-12)) [](#__codelineno-15-13)[](#__codelineno-15-14)clear_tasks_button = mo.ui.button( [](#__codelineno-15-15) label="clear completed tasks", [](#__codelineno-15-16) on_change=lambda _: clear_tasks() [](#__codelineno-15-17))` `[](#__codelineno-16-1)task_list = mo.ui.array( [](#__codelineno-16-2) [mo.ui.checkbox(value=task.done, label=task.name) for task in get_tasks()], [](#__codelineno-16-3) label="tasks", [](#__codelineno-16-4) on_change=lambda v: set_tasks( [](#__codelineno-16-5) lambda tasks: [Task(task.name, done=v[i]) for i, task in enumerate(tasks)] [](#__codelineno-16-6) ), [](#__codelineno-16-7))` `[](#__codelineno-17-1)inputs = mo.hstack( [](#__codelineno-17-2) [task_entry_box, add_task_button, clear_tasks_button], justify="start" [](#__codelineno-17-3)) [](#__codelineno-17-4)mo.vstack([inputs, task_list])` Markdown - marimo https://docs.marimo.io/api/markdown/ Write markdown with `mo.md`; make your markdown **interactive**, **dynamic**, and **visually rich** by interpolating arbitrary Python values and marimo elements. marimo.md [¶](#marimo.md "Permanent link") ------------------------------------------ Write markdown This function takes a string of markdown as input and returns an Html object. Output the object as the last expression of a cell to render the markdown in your app. **Interpolation.** You can interpolate Python values into your markdown strings, for example using f-strings. Html objects and UI elements can be directly interpolated. For example: `[](#__codelineno-0-1)text_input = mo.ui.text() [](#__codelineno-0-2)md(f"Enter some text: {text_input}")` For other objects, like plots, use marimo's `as_html` method to embed them in markdown: `[](#__codelineno-1-1)import matplotlib.pyplot as plt [](#__codelineno-1-2)[](#__codelineno-1-3)plt.plot([1, 2]) [](#__codelineno-1-4)axis = plt.gca() [](#__codelineno-1-5)md(f"Here's a plot: {mo.as_html(axis)}")` **LaTeX.** Enclose LaTeX in single '$' signs for inline math, and double '$$' for display math or square brackets for display math. (Use raw strings, prefixed with an "r", to use single backslashes.) For example: `[](#__codelineno-2-1)mo.md( [](#__codelineno-2-2) r''' [](#__codelineno-2-3) The exponential function $f(x) = e^x$ can be represented as [](#__codelineno-2-4) [](#__codelineno-2-5) \[ [](#__codelineno-2-6) f(x) = 1 + x + \frac{x^2}{2!} + \frac{x^3}{3!} + \ldots. [](#__codelineno-2-7) \] [](#__codelineno-2-8) ''' [](#__codelineno-2-9))` renders: The exponential function \\(f(x) = e^x\\) can be represented as \\\[ f(x) = 1 + x + \\frac{x^2}{2!} + \\frac{x^3}{3!} + \\ldots. \\\] | PARAMETER | DESCRIPTION | | --- | --- | | `text` | a string of markdown **TYPE:** `str` | | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | Loading LaTeX macros[¶](#loading-latex-macros "Permanent link") --------------------------------------------------------------- You can load LaTeX macros using `mo.latex(filename=...)`. marimo.latex [¶](#marimo.latex "Permanent link") ------------------------------------------------ `[](#__codelineno-0-1)latex(*, filename: str | Path) -> None` Load LaTeX from a file or URL. `[](#__codelineno-0-1)import marimo as mo [](#__codelineno-0-2)[](#__codelineno-0-3)mo.latex(filename="macros.tex")` or `[](#__codelineno-1-1)import marimo as mo [](#__codelineno-1-2)[](#__codelineno-1-3)mo.latex(filename="https://example.com/macros.tex")` | PARAMETER | DESCRIPTION | | --- | --- | | `filename` | Path to a LaTeX file **TYPE:** `str | Path` | | RETURNS | DESCRIPTION | | --- | --- | | `None` | An `Html` object | Side effects The `mo.latex()` function has side effects (registering the LaTeX macros) and should be used in the same cell as `import marimo`. Otherwise, the LaTeX macros may not be loaded before the cells that use them. Icons[¶](#icons "Permanent link") --------------------------------- We support rendering icons from [Iconify](https://icon-sets.iconify.design/). When is inside markdown, you can render an icon with the syntax `::iconset:icon-name::` for example `::lucide:rocket::` or `::mdi:home::`. This is useful for quickly adding an icon, however, it does not support advanced configuration such as size, color, and rotation. For other advanced features, use `mo.icon()` such as `mo.icon("lucide:rocket", size=20)` or `mo.icon("mdi:home", color="blue")`. marimo.icon [¶](#marimo.icon "Permanent link") ---------------------------------------------- `[](#__codelineno-0-1)icon( [](#__codelineno-0-2) icon_name: str, [](#__codelineno-0-3) *, [](#__codelineno-0-4) size: int | None = None, [](#__codelineno-0-5) color: str | None = None, [](#__codelineno-0-6) inline: bool = True, [](#__codelineno-0-7) flip: Literal[ [](#__codelineno-0-8) "horizontal", "vertical", "horizontal,vertical" [](#__codelineno-0-9) ] [](#__codelineno-0-10) | None = None, [](#__codelineno-0-11) rotate: Literal["90deg", "180deg", "270deg"] [](#__codelineno-0-12) | None = None, [](#__codelineno-0-13) style: dict[str, str | int | float | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Displays an icon. These icons are referenced by name from the [Iconify](https://iconify.design/) library. They are named in the format `icon-set:icon-name`, e.g. `lucide:leaf`. Icons are lazily loaded from a CDN, so they will not be loaded when not connected to the internet. These can be used in buttons, tabs, and other UI elements. Examples: `[](#__codelineno-0-1)mo.md(f"# {mo.icon('lucide:leaf')} Leaf") [](#__codelineno-0-2)[](#__codelineno-0-3)mo.ui.button( [](#__codelineno-0-4) label=f"{mo.icon('lucide:rocket')} Submit", [](#__codelineno-0-5))` | PARAMETER | DESCRIPTION | | --- | --- | | `icon_name` | the name of the icon to display **TYPE:** `str` | | `size` | the size of the icon in pixels **TYPE:** `int | None` **DEFAULT:** `None` | | `color` | the color of the icon **TYPE:** `str | None` **DEFAULT:** `None` | | `inline` | whether to display the icon inline or as a block element **TYPE:** `bool` **DEFAULT:** `True` | | `flip` | whether to flip the icon horizontally, vertically, or both **TYPE:** `Literal['horizontal', 'vertical', 'horizontal,vertical'] | None` **DEFAULT:** `None` | | `rotate` | whether to rotate the icon 90, 180, or 270 degrees **TYPE:** `Literal['90deg', '180deg', '270deg'] | None` **DEFAULT:** `None` | | `style` | a dictionary of CSS styles to apply to the icon **TYPE:** `dict[str, str | int | float | None] | None` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | --- | --- | | `Html` | An `Html` object. **TYPE:** `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | You can render a tooltip by adding the `data-tooltip` attribute to an element. `[](#__codelineno-0-1)mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3)
Hover over me
[](#__codelineno-0-4) ''' [](#__codelineno-0-5)) [](#__codelineno-0-6)mo.ui.button( [](#__codelineno-0-7) label='
Hover over me
' [](#__codelineno-0-8))` Rendering images[¶](#rendering-images "Permanent link") ------------------------------------------------------- You can render images from a local `public/` folder: `[](#__codelineno-1-1)mo.md( [](#__codelineno-1-2) ''' [](#__codelineno-1-3) [](#__codelineno-1-4) ''' [](#__codelineno-1-5))` See [Static files](https://docs.marimo.io/guides/outputs/#static-files) for information about serving images and other static assets.
Recipes - marimo https://docs.marimo.io/recipes/ This page includes code snippets or "**recipes**" for a variety of common tasks. Use them as building blocks or examples when making your own notebooks. In these recipes, **each code block represents a cell**. Control Flow[¶](#control-flow "Permanent link") ----------------------------------------------- ### Show an output conditionally[¶](#show-an-output-conditionally "Permanent link") **Use cases.** Hide an output until a condition is met (_e.g._, until algorithm parameters are valid), or show different outputs depending on the value of a UI element or some other Python object **Recipe.** 1. Use an `if` expression to choose which output to show. `[](#__codelineno-0-1)# condition is a boolean, True of False [](#__codelineno-0-2)condition = True [](#__codelineno-0-3)"condition is True" if condition else None` ### Run a cell on a timer[¶](#run-a-cell-on-a-timer "Permanent link") **Use cases.** * Load new data periodically, and show updated plots or other outputs. For example, in a dashboard monitoring a training run, experiment trial, real-time weather data, ... * Run a job periodically **Recipe.** 1. Import packages 2. Create a [`mo.ui.refresh`](https://docs.marimo.io/api/inputs/refresh/#marimo.ui.refresh " marimo.ui.refresh") timer that fires once a second: `[](#__codelineno-2-1)refresh = mo.ui.refresh(default_interval="1s") [](#__codelineno-2-2)# This outputs a timer that fires once a second [](#__codelineno-2-3)refresh` 3. Reference the timer by name to make this cell run once a second `[](#__codelineno-3-1)import random [](#__codelineno-3-2)[](#__codelineno-3-3)# This cell will run once a second! [](#__codelineno-3-4)refresh [](#__codelineno-3-5)[](#__codelineno-3-6)mo.md("#" + "🍃" * random.randint(1, 10))` Requires 'on cell change' autorun For this to work, the [runtime configuration's](https://docs.marimo.io/guides/configuration/runtime_configuration/) `on cell change` should be set to `autorun` ### Require form submission before sending UI value[¶](#require-form-submission-before-sending-ui-value "Permanent link") **Use cases.** UI elements automatically send their values to the Python when they are interacted with, and run all cells referencing the elements. This makes marimo notebooks responsive, but it can be an issue when the downstream cells are expensive, or when the input (such as a text box) needs to be filled out completely before it is considered valid. Forms let you gate submission of UI element values on manual confirmation, via a button press. **Recipe.** 1. Import packages 2. Create a submittable form. `[](#__codelineno-5-1)form = mo.ui.text(label="Your name").form() [](#__codelineno-5-2)form` 3. Get the value of the form. ### Stop execution of a cell and its descendants[¶](#stop-execution-of-a-cell-and-its-descendants "Permanent link") **Use cases.** For example, don't run a cell or its descendants if a form is unsubmitted. **Recipe.** 1. Import packages 2. Create a submittable form. `[](#__codelineno-8-1)form = mo.ui.text(label="Your name").form() [](#__codelineno-8-2)form` 3. Use [`mo.stop`](https://docs.marimo.io/api/control_flow/#marimo.stop " marimo.stop") to stop execution when the form is unsubmitted. `[](#__codelineno-9-1)mo.stop(form.value is None, mo.md("Submit the form to continue")) [](#__codelineno-9-2)[](#__codelineno-9-3)mo.md(f"Hello, {form.value}!")` Grouping UI elements together[¶](#grouping-ui-elements-together "Permanent link") --------------------------------------------------------------------------------- ### Create an array of UI elements[¶](#create-an-array-of-ui-elements "Permanent link") **Use cases.** In order to synchronize UI elements between the frontend and backend (Python), marimo requires you to [assign UI elements to global variables](https://docs.marimo.io/guides/interactivity/). But sometimes you don't know the number of elements to make until runtime: for example, maybe you want to make a list of sliders, and the number of sliders to make depends on the value of some other UI element. You might be tempted to create a Python list of UI elements, such as `l = [mo.ui.slider(1, 10) for i in range(number.value)]`: _however, this won't work, because the sliders are not bound to global variables_. For such cases, marimo provides the "higher-order" UI element [`mo.ui.array`](https://docs.marimo.io/api/inputs/array/#marimo.ui.array " marimo.ui.array"), which lets you make a new UI element out of a list of UI elements: `l = mo.ui.array([mo.ui.slider(1, 10) for i in range(number.value)])`. The value of an `array` element is a list of the values of the elements it wraps (in this case, a list of the slider values). Any time you interact with any of the UI elements in the array, all cells referencing the array by name (in this case, "`l`") will run automatically. **Recipe.** 1. Import packages. 2. Use [`mo.ui.array`](https://docs.marimo.io/api/inputs/array/#marimo.ui.array " marimo.ui.array") to group together many UI elements into a list. `[](#__codelineno-11-1)import random [](#__codelineno-11-2)[](#__codelineno-11-3)# instead of random.randint, in your notebook you'd use the value of [](#__codelineno-11-4)# an upstream UI element or other Python object [](#__codelineno-11-5)array = mo.ui.array([mo.ui.text() for i in range(random.randint(1, 10))]) [](#__codelineno-11-6)array` 3. Get the value of the UI elements using `array.value` ### Create a dictionary of UI elements[¶](#create-a-dictionary-of-ui-elements "Permanent link") **Use cases.** Same as for creating an array of UI elements, but lets you name each of the wrapped elements with a string key. **Recipe.** 1. Import packages. 2. Use [`mo.ui.dictionary`](https://docs.marimo.io/api/inputs/dictionary/#marimo.ui.dictionary " marimo.ui.dictionary") to group together many UI elements into a list. `[](#__codelineno-14-1)import random [](#__codelineno-14-2)[](#__codelineno-14-3)# instead of random.randint, in your notebook you'd use the value of [](#__codelineno-14-4)# an upstream UI element or other Python object [](#__codelineno-14-5)dictionary = mo.ui.dictionary({str(i): mo.ui.text() for i in range(random.randint(1, 10))}) [](#__codelineno-14-6)dictionary` 3. Get the value of the UI elements using `dictionary.value` ### Embed a dynamic number of UI elements in another output[¶](#embed-a-dynamic-number-of-ui-elements-in-another-output "Permanent link") **Use cases.** When you want to embed a dynamic number of UI elements in other outputs (like tables or markdown). **Recipe.** 1. Import packages 2. Group the elements with [`mo.ui.dictionary`](https://docs.marimo.io/api/inputs/dictionary/#marimo.ui.dictionary " marimo.ui.dictionary") or [`mo.ui.array`](https://docs.marimo.io/api/inputs/array/#marimo.ui.array " marimo.ui.array"), then retrieve them from the container and display them elsewhere. ``[](#__codelineno-17-1)import random [](#__codelineno-17-2)[](#__codelineno-17-3)n_items = random.randint(2, 5) [](#__codelineno-17-4)[](#__codelineno-17-5)# Create a dynamic number of elements using `mo.ui.dictionary` and [](#__codelineno-17-6)# `mo.ui.array` [](#__codelineno-17-7)elements = mo.ui.dictionary( [](#__codelineno-17-8) { [](#__codelineno-17-9) "checkboxes": mo.ui.array([mo.ui.checkbox() for _ in range(n_items)]), [](#__codelineno-17-10) "texts": mo.ui.array( [](#__codelineno-17-11) [mo.ui.text(placeholder="task ...") for _ in range(n_items)] [](#__codelineno-17-12) ), [](#__codelineno-17-13) } [](#__codelineno-17-14)) [](#__codelineno-17-15)[](#__codelineno-17-16)mo.md( [](#__codelineno-17-17) f""" [](#__codelineno-17-18) Here's a TODO list of {n_items} items\n\n [](#__codelineno-17-19) """ [](#__codelineno-17-20) + "\n\n".join( [](#__codelineno-17-21) # Iterate over the elements and embed them in markdown [](#__codelineno-17-22) [ [](#__codelineno-17-23) f"{checkbox} {text}" [](#__codelineno-17-24) for checkbox, text in zip( [](#__codelineno-17-25) elements["checkboxes"], elements["texts"] [](#__codelineno-17-26) ) [](#__codelineno-17-27) ] [](#__codelineno-17-28) ) [](#__codelineno-17-29))`` 3. Get the value of the elements ### Create a hstack (or vstack) of UI elements with `on_change` handlers[¶](#create-a-hstack-or-vstack-of-ui-elements-with-on_change-handlers "Permanent link") **Use cases.** Arrange a dynamic number of UI elements in a hstack or vstack, for example some number of buttons, and execute some side-effect when an element is interacted with, e.g. when a button is clicked. **Recipe.** 1. Import packages 2. Create buttons in `mo.ui.array` and pass them to hstack -- a regular Python list won't work. Make sure to assign the array to a global variable. `[](#__codelineno-20-1)import random [](#__codelineno-20-2) [](#__codelineno-20-3)[](#__codelineno-20-4)# Create a state object that will store the index of the [](#__codelineno-20-5)# clicked button [](#__codelineno-20-6)get_state, set_state = mo.state(None) [](#__codelineno-20-7)[](#__codelineno-20-8)# Create an mo.ui.array of buttons - a regular Python list won't work. [](#__codelineno-20-9)buttons = mo.ui.array( [](#__codelineno-20-10) [ [](#__codelineno-20-11) mo.ui.button( [](#__codelineno-20-12) label="button " + str(i), on_change=lambda v, i=i: set_state(i) [](#__codelineno-20-13) ) [](#__codelineno-20-14) for i in range(random.randint(2, 5)) [](#__codelineno-20-15) ] [](#__codelineno-20-16)) [](#__codelineno-20-17)[](#__codelineno-20-18)mo.hstack(buttons)` 3. Get the state value ### Create a table column of buttons with `on_change` handlers[¶](#create-a-table-column-of-buttons-with-on_change-handlers "Permanent link") **Use cases.** Arrange a dynamic number of UI elements in a column of a table, and execute some side-effect when an element is interacted with, e.g. when a button is clicked. **Recipe.** 1. Import packages 2. Create buttons in `mo.ui.array` and pass them to `mo.ui.table`. Make sure to assign the table and array to global variables `[](#__codelineno-23-1)import random [](#__codelineno-23-2) [](#__codelineno-23-3)[](#__codelineno-23-4)# Create a state object that will store the index of the [](#__codelineno-23-5)# clicked button [](#__codelineno-23-6)get_state, set_state = mo.state(None) [](#__codelineno-23-7)[](#__codelineno-23-8)# Create an mo.ui.array of buttons - a regular Python list won't work. [](#__codelineno-23-9)buttons = mo.ui.array( [](#__codelineno-23-10) [ [](#__codelineno-23-11) mo.ui.button( [](#__codelineno-23-12) label="button " + str(i), on_change=lambda v, i=i: set_state(i) [](#__codelineno-23-13) ) [](#__codelineno-23-14) for i in range(random.randint(2, 5)) [](#__codelineno-23-15) ] [](#__codelineno-23-16)) [](#__codelineno-23-17)[](#__codelineno-23-18)# Put the buttons array into the table [](#__codelineno-23-19)table = mo.ui.table( [](#__codelineno-23-20) { [](#__codelineno-23-21) "Action": ["Action Name"] * len(buttons), [](#__codelineno-23-22) "Trigger": list(buttons), [](#__codelineno-23-23) } [](#__codelineno-23-24)) [](#__codelineno-23-25)table` 3. Get the state value ### Create a form with multiple UI elements[¶](#create-a-form-with-multiple-ui-elements "Permanent link") **Use cases.** Combine multiple UI elements into a form so that submission of the form sends all its elements to Python. **Recipe.** 1. Import packages. 2. Use [`mo.ui.form`](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form") and [`Html.batch`](https://docs.marimo.io/api/html/#marimo.Html.batch " batch") to create a form with multiple elements. `[](#__codelineno-26-1)form = mo.md( [](#__codelineno-26-2) r""" [](#__codelineno-26-3) Choose your algorithm parameters: [](#__codelineno-26-4) [](#__codelineno-26-5) - $\epsilon$: {epsilon} [](#__codelineno-26-6) - $\delta$: {delta} [](#__codelineno-26-7) """ [](#__codelineno-26-8)).batch(epsilon=mo.ui.slider(0.1, 1, step=0.1), delta=mo.ui.number(1, 10)).form() [](#__codelineno-26-9)form` 3. Get the submitted form value. ### Populating form with pre-defined examples[¶](#populating-form-with-pre-defined-examples "Permanent link") **Use cases.** To give examples of how a filled form looks like. Useful for illustrating complex API requests or database queries. The form can also be populated from [URL query parameters](https://docs.marimo.io/api/query_params/) ([notebook example](https://marimo.app/l/w21a3x?t1=query&t2=params)). **Recipe.** 1. Import packages 2. Create dropdown of examples `[](#__codelineno-29-1)examples = mo.ui.dropdown( [](#__codelineno-29-2) options={ [](#__codelineno-29-3) "ex 1": {"t1": "hello", "t2": "world"}, [](#__codelineno-29-4) "ex 2": {"t1": "marimo", "t2": "notebook"}, [](#__codelineno-29-5) }, [](#__codelineno-29-6) value="ex 1", [](#__codelineno-29-7) label="examples", [](#__codelineno-29-8))` 3. Create form from examples. `[](#__codelineno-30-1)form = ( [](#__codelineno-30-2) mo.md( [](#__codelineno-30-3) """ [](#__codelineno-30-4) ### Your form [](#__codelineno-30-5) [](#__codelineno-30-6) {t1} [](#__codelineno-30-7) {t2} [](#__codelineno-30-8)""" [](#__codelineno-30-9) ) [](#__codelineno-30-10) .batch( [](#__codelineno-30-11) t1=mo.ui.text(label="enter text", value=examples.value.get("t1", "")), [](#__codelineno-30-12) t2=mo.ui.text(label="more text", value=examples.value.get("t2", "")), [](#__codelineno-30-13) ) [](#__codelineno-30-14) .form( [](#__codelineno-30-15) submit_button_label="go" [](#__codelineno-30-16) ) [](#__codelineno-30-17))` 4. Run pre-populated from or recompute with new input. `[](#__codelineno-31-1)output = ( [](#__codelineno-31-2) " ".join(form.value.values()).upper() [](#__codelineno-31-3) if form.value is not None [](#__codelineno-31-4) else " ".join(examples.value.values()).upper() [](#__codelineno-31-5)) [](#__codelineno-31-6)examples, form, output` Working with buttons[¶](#working-with-buttons "Permanent link") --------------------------------------------------------------- ### Create a button that triggers computation when clicked[¶](#create-a-button-that-triggers-computation-when-clicked "Permanent link") **Use cases.** To trigger a computation on button click and only on button click, use [`mo.ui.run_button()`](https://docs.marimo.io/api/inputs/run_button/). **Recipe.** 1. Import packages 2. Create a run button `[](#__codelineno-33-1)button = mo.ui.run_button() [](#__codelineno-33-2)button` 3. Run something only if the button has been clicked. `[](#__codelineno-34-1)mo.stop(not button.value, "Click 'run' to generate a random number") [](#__codelineno-34-2)[](#__codelineno-34-3)import random [](#__codelineno-34-4)random.randint(0, 1000)` ### Create a counter button[¶](#create-a-counter-button "Permanent link") **Use cases.** A counter button, i.e. a button that counts the number of times it has been clicked, is a helpful building block for reacting to button clicks (see other recipes in this section). **Recipe.** 1. Import packages 2. Use [`mo.ui.button`](https://docs.marimo.io/api/inputs/button/#marimo.ui.button " marimo.ui.button") and its `on_click` argument to create a counter button. `[](#__codelineno-36-1)# Initialize the button value to 0, increment it on every click [](#__codelineno-36-2)button = mo.ui.button(value=0, on_click=lambda count: count + 1) [](#__codelineno-36-3)button` 3. Get the button value ### Create a toggle button[¶](#create-a-toggle-button "Permanent link") **Use cases.** Toggle between two states using a button with a button that toggles between `True` and `False`. (Tip: you can also just use [`mo.ui.switch`](https://docs.marimo.io/api/inputs/switch/#marimo.ui.switch " marimo.ui.switch").) **Recipe.** 1. Import packages 2. Use [`mo.ui.button`](https://docs.marimo.io/api/inputs/button/#marimo.ui.button " marimo.ui.button") and its `on_click` argument to create a toggle button. `[](#__codelineno-39-1)# Initialize the button value to False, flip its value on every click. [](#__codelineno-39-2)button = mo.ui.button(value=False, on_click=lambda value: not value) [](#__codelineno-39-3)button` 3. Toggle between two outputs using the button value. `[](#__codelineno-40-1)mo.md("True!") if button.value else mo.md("False!")` ### Re-run a cell when a button is pressed[¶](#re-run-a-cell-when-a-button-is-pressed "Permanent link") **Use cases.** For example, you have a cell showing a random sample of data, and you want to resample on button press. **Recipe.** 1. Import packages 2. Create a button without a value, to function as a _trigger_. `[](#__codelineno-42-1)button = mo.ui.button() [](#__codelineno-42-2)button` 3. Reference the button in another cell. `[](#__codelineno-43-1)# the button acts as a trigger: every time it is clicked, this cell is run [](#__codelineno-43-2)button [](#__codelineno-43-3)[](#__codelineno-43-4)# Replace with your custom logic [](#__codelineno-43-5)import random [](#__codelineno-43-6)random.randint(0, 100)` ### Run a cell when a button is pressed, but not before[¶](#run-a-cell-when-a-button-is-pressed-but-not-before "Permanent link") **Use cases.** Wait for confirmation before executing downstream cells (similar to a form). **Recipe.** 1. Import packages 2. Create a counter button. `[](#__codelineno-45-1)button = mo.ui.button(value=0, on_click=lambda count: count + 1) [](#__codelineno-45-2)button` 3. Only execute when the count is greater than 0. `[](#__codelineno-46-1)# Don't run this cell if the button hasn't been clicked, using mo.stop. [](#__codelineno-46-2)# Alternatively, use an if expression. [](#__codelineno-46-3)mo.stop(button.value == 0) [](#__codelineno-46-4)[](#__codelineno-46-5)mo.md(f"The button was clicked {button.value} times")` ### Reveal an output when a button is pressed[¶](#reveal-an-output-when-a-button-is-pressed "Permanent link") **Use cases.** Incrementally reveal a user interface. **Recipe.** 1. Import packages 2. Create a counter button. `[](#__codelineno-48-1)button = mo.ui.button(value=0, on_click=lambda count: count + 1) [](#__codelineno-48-2)button` 3. Show an output after the button is clicked. `[](#__codelineno-49-1)mo.md("#" + "🍃" * button.value) if button.value > 0 else None` Caching[¶](#caching "Permanent link") ------------------------------------- ### Cache function outputs in memory[¶](#cache-function-outputs-in-memory "Permanent link") **Use case.** Because marimo runs cells automatically as code and UI elements change, it can be helpful to cache expensive intermediate computations. For example, perhaps your notebook computes t-SNE, UMAP, or PyMDE embeddings, and exposes their parameters as UI elements. Caching the embeddings for different configurations of the elements would greatly speed up your notebook. **Recipe.** 1. Use [`mo.cache`](https://docs.marimo.io/api/caching/#marimo.cache " marimo.cache") to cache function outputs given inputs. `[](#__codelineno-50-1)import marimo as mo [](#__codelineno-50-2)[](#__codelineno-50-3)@mo.cache [](#__codelineno-50-4)def compute_predictions(problem_parameters): [](#__codelineno-50-5) # replace with your own function/parameters [](#__codelineno-50-6) ...` Whenever `compute_predictions` is called with a value of `problem_parameters` it has not seen, it will compute the predictions and store them in a cache. The next time it is called with the same parameters, instead of recomputing the predictions, it will return the previously computed value from the cache. ### Persistent caching for very expensive computations[¶](#persistent-caching-for-very-expensive-computations "Permanent link") **Use case.** If you are using marimo to capture very compute intensive results, you may want to save the state of your computations to disk. Ideally, if you update your code, then this save should be invalidated. It may also be advantageous to add UI elements to explore your results, without having to recompute expensive computations. You can achieve this with [`mo.persistent_cache`](https://docs.marimo.io/api/caching/#marimo.persistent_cache " marimo.persistent_cache"). **Recipe.** 1. Use `mo.persistent_cache` to cache blocks of code to disk. `[](#__codelineno-51-1)import marimo as mo [](#__codelineno-51-2)[](#__codelineno-51-3)with mo.persistent_cache("my_cache"): [](#__codelineno-51-4) # This block of code, and results will be cached to disk [](#__codelineno-51-5) ...` If the execution conditions are the same, then cache will load results from disk, and populate variable definitions. Inputs - marimo https://docs.marimo.io/api/inputs/ marimo comes packaged with interactive UI elements that you can use to build powerful notebooks and apps. These elements are available in `marimo.ui`. | Element | Description | | --- | --- | | [`marimo.ui.array`](https://docs.marimo.io/api/inputs/array/#marimo.ui.array " marimo.ui.array") | Create array inputs | | [`marimo.ui.batch`](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch") | Batch operations | | [`marimo.ui.button`](https://docs.marimo.io/api/inputs/button/#marimo.ui.button " marimo.ui.button") | Create buttons | | [`marimo.ui.chat`](https://docs.marimo.io/api/inputs/chat/#marimo.ui.chat " marimo.ui.chat") | Create chat interfaces | | [`marimo.ui.checkbox`](https://docs.marimo.io/api/inputs/checkbox/#marimo.ui.checkbox " marimo.ui.checkbox") | Create checkboxes | | [`marimo.ui.code_editor`](https://docs.marimo.io/api/inputs/code_editor/#marimo.ui.code_editor " marimo.ui.code_editor") | Create code editors | | [`marimo.ui.dataframe`](https://docs.marimo.io/api/inputs/dataframe/#marimo.ui.dataframe " marimo.ui.dataframe") | Interactive dataframes | | [`marimo.ui.data_explorer`](https://docs.marimo.io/api/inputs/data_explorer/#marimo.ui.data_explorer " marimo.ui.data_explorer") | Explore data | | [`marimo.ui.date`](https://docs.marimo.io/api/inputs/dates/#marimo.ui.date " marimo.ui.date") | Date picker | | [`marimo.ui.datetime`](https://docs.marimo.io/api/inputs/dates/#marimo.ui.datetime " marimo.ui.datetime") | Date and time picker | | [`marimo.ui.date_range`](https://docs.marimo.io/api/inputs/dates/#marimo.ui.date_range " marimo.ui.date_range") | Date range picker | | [`marimo.ui.dictionary`](https://docs.marimo.io/api/inputs/dictionary/#marimo.ui.dictionary " marimo.ui.dictionary") | Dictionary inputs | | [`marimo.ui.dropdown`](https://docs.marimo.io/api/inputs/dropdown/#marimo.ui.dropdown " marimo.ui.dropdown") | Create dropdowns | | [`marimo.ui.file`](https://docs.marimo.io/api/inputs/file/#marimo.ui.file " marimo.ui.file") | File uploads | | [`marimo.ui.file_browser`](https://docs.marimo.io/api/inputs/file_browser/#marimo.ui.file_browser " marimo.ui.file_browser") | Browse files | | [`marimo.ui.form`](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form") | Create forms | | [`marimo.ui.matrix`](https://docs.marimo.io/api/inputs/matrix/#marimo.ui.matrix " marimo.ui.matrix") | Interactive matrix/vector editor | | [`marimo.ui.microphone`](https://docs.marimo.io/api/inputs/microphone/#marimo.ui.microphone " marimo.ui.microphone") | Record audio | | [`marimo.ui.multiselect`](https://docs.marimo.io/api/inputs/multiselect/#marimo.ui.multiselect " marimo.ui.multiselect") | Multiple selection | | [`marimo.ui.number`](https://docs.marimo.io/api/inputs/number/#marimo.ui.number " marimo.ui.number") | Number inputs | | [`marimo.ui.radio`](https://docs.marimo.io/api/inputs/radio/#marimo.ui.radio " marimo.ui.radio") | Radio buttons | | [`marimo.ui.range_slider`](https://docs.marimo.io/api/inputs/range_slider/#marimo.ui.range_slider " marimo.ui.range_slider") | Range sliders | | [`marimo.ui.refresh`](https://docs.marimo.io/api/inputs/refresh/#marimo.ui.refresh " marimo.ui.refresh") | Refresh buttons | | [`marimo.ui.run_button`](https://docs.marimo.io/api/inputs/run_button/#marimo.ui.run_button " marimo.ui.run_button") | Run buttons | | [`marimo.ui.slider`](https://docs.marimo.io/api/inputs/slider/#marimo.ui.slider " marimo.ui.slider") | Create sliders | | [`marimo.ui.switch`](https://docs.marimo.io/api/inputs/switch/#marimo.ui.switch " marimo.ui.switch") | Toggle switches | | [`marimo.ui.tabs`](https://docs.marimo.io/api/inputs/tabs/#marimo.ui.tabs " marimo.ui.tabs") | Tabbed interfaces | | [`marimo.ui.table`](https://docs.marimo.io/api/inputs/table/#marimo.ui.table " marimo.ui.table") | Interactive tables | | [`marimo.ui.text`](https://docs.marimo.io/api/inputs/text/#marimo.ui.text " marimo.ui.text") | Text inputs | | [`marimo.ui.text_area`](https://docs.marimo.io/api/inputs/text_area/#marimo.ui.text_area " marimo.ui.text_area") | Multiline text inputs | To use a UI element, assign it to a global variable and output it in a cell. When you interact with the frontend element, the Python object's `value` attribute is automatically updated, and all cells referencing that object automatically run with the element's latest value. Integrations[¶](#integrations "Permanent link") ----------------------------------------------- | Integration | Description | | --- | --- | | [`marimo.ui.altair_chart`](https://docs.marimo.io/api/plotting/#marimo.ui.altair_chart " marimo.ui.altair_chart") | Interactive Altair charts | | [`marimo.ui.matplotlib`](https://docs.marimo.io/api/plotting/#marimo.ui.matplotlib " marimo.ui.matplotlib") | Reactive Matplotlib plots | | [`marimo.ui.plotly`](https://docs.marimo.io/api/plotting/#marimo.ui.plotly " marimo.ui.plotly") | Interactive Plotly charts | | [`marimo.ui.anywidget`](https://docs.marimo.io/api/inputs/anywidget/#marimo.ui.anywidget " marimo.ui.anywidget") | Custom widgets | AnyWidget - marimo https://docs.marimo.io/api/inputs/anywidget/ Building custom UI elements[¶](#building-custom-ui-elements "Permanent link") ----------------------------------------------------------------------------- Build custom UI plugins that hook into marimo's reactive execution engine by using [anywidget](https://anywidget.dev/). [anywidget](https://anywidget.dev/) is a Python library and specification for creating custom Jupyter-compatible widgets. marimo supports anywidget, allowing you to import anywidget widgets or create your own custom widgets and use them in your notebooks and apps. You can use anywidgets that others have built, such as [quak](https://github.com/manzt/quak) or [drawdata](https://github.com/koaning/drawdata), directly in marimo. Here is an example using `drawdata`: `[](#__codelineno-0-1)# pip install drawdata [](#__codelineno-0-2)from drawdata import ScatterWidget [](#__codelineno-0-3)[](#__codelineno-0-4)# Don't forget to wrap the widget with marimo.ui.anywidget [](#__codelineno-0-5)widget = mo.ui.anywidget(ScatterWidget()) [](#__codelineno-0-6)[](#__codelineno-0-7)# In another cell, you can access the widget's value [](#__codelineno-0-8)widget.value [](#__codelineno-0-9)[](#__codelineno-0-10)# You can also access the widget's specific properties [](#__codelineno-0-11)widget.data [](#__codelineno-0-12)widget.data_as_polars` For additional examples, see [our repo](https://github.com/marimo-team/marimo/tree/main/examples/third_party/anywidget) or our [widgets gallery](https://marimo.io/gallery/widgets). Anywidget lets you write custom widgets by adding JavaScript to your Python code. Below is an example of a counter widget. ``[](#__codelineno-1-1)import anywidget [](#__codelineno-1-2)import traitlets [](#__codelineno-1-3)import marimo as mo [](#__codelineno-1-4)[](#__codelineno-1-5)class CounterWidget(anywidget.AnyWidget): [](#__codelineno-1-6) # Widget front-end JavaScript code [](#__codelineno-1-7) _esm = """ [](#__codelineno-1-8) function render({ model, el }) { [](#__codelineno-1-9) let getCount = () => model.get("count"); [](#__codelineno-1-10) let button = document.createElement("button"); [](#__codelineno-1-11) button.innerHTML = `count is ${getCount()}`; [](#__codelineno-1-12) button.addEventListener("click", () => { [](#__codelineno-1-13) model.set("count", getCount() + 1); [](#__codelineno-1-14) model.save_changes(); [](#__codelineno-1-15) }); [](#__codelineno-1-16) model.on("change:count", () => { [](#__codelineno-1-17) button.innerHTML = `count is ${getCount()}`; [](#__codelineno-1-18) }); [](#__codelineno-1-19) el.appendChild(button); [](#__codelineno-1-20) } [](#__codelineno-1-21) export default { render }; [](#__codelineno-1-22) """ [](#__codelineno-1-23) _css = """ [](#__codelineno-1-24) button { [](#__codelineno-1-25) padding: 5px !important; [](#__codelineno-1-26) border-radius: 5px !important; [](#__codelineno-1-27) background-color: #f0f0f0 !important; [](#__codelineno-1-28) [](#__codelineno-1-29) &:hover { [](#__codelineno-1-30) background-color: lightblue !important; [](#__codelineno-1-31) color: white !important; [](#__codelineno-1-32) } [](#__codelineno-1-33) } [](#__codelineno-1-34) """ [](#__codelineno-1-35) [](#__codelineno-1-36) # Stateful property that can be accessed by JavaScript & Python [](#__codelineno-1-37) [](#__codelineno-1-38) count = traitlets.Int(0).tag(sync=True) [](#__codelineno-1-39)[](#__codelineno-1-40)widget = mo.ui.anywidget(CounterWidget()) [](#__codelineno-1-41) [](#__codelineno-1-42)[](#__codelineno-1-43)# In another cell, you can access the widget's value [](#__codelineno-1-44)widget.value [](#__codelineno-1-45)[](#__codelineno-1-46)# You can also access the widget's specific properties [](#__codelineno-1-47)widget.count`` ### More examples[¶](#more-examples "Permanent link") If you're eager to build your own widgets and want to dive deeper you may enjoy these resources: * Before making your own widget, it would be best to check and see if the widget already exists. The [widgets section on the marimo gallery](https://marimo.io/gallery/widgets) as well as the [gallery on anywidget.dev](https://anywidget.dev/en/community/) give you a good overview of what's out there. * The [wigglystuff repository](https://github.com/koaning/wigglystuff) has many smaller widgets that could serve as an excellent starting point. * We've noticed that coding agents are getting better at generating these anywidgets on the fly. If you're keen to explore that you can check out our [prompts section](https://docs.marimo.io/guides/generate_with_ai/prompts/#anywidget) for a quickstart. * You may also enjoy [this livestream on the marimo YouTube channel](https://www.youtube.com/watch?v=3V1r5sKnyz8) on building anywidgets. * * * `[](#__codelineno-0-1)anywidget(widget: AnyWidget)` Bases: `UIElement[ModelIdRef, AnyWidgetState]` Create a UIElement from an AnyWidget. This proxies all the widget's attributes and methods, allowing seamless integration of AnyWidget instances with Marimo's UI system. Examples: `[](#__codelineno-0-1)from drawdata import ScatterWidget [](#__codelineno-0-2)import marimo as mo [](#__codelineno-0-3)[](#__codelineno-0-4)scatter = ScatterWidget() [](#__codelineno-0-5)scatter = mo.ui.anywidget(scatter) [](#__codelineno-0-6)[](#__codelineno-0-7)# In another cell, access its value [](#__codelineno-0-8)# This works for all widgets [](#__codelineno-0-9)scatter.value [](#__codelineno-0-10)[](#__codelineno-0-11)# Or attributes specifically on the ScatterWidget [](#__codelineno-0-12)scatter.data_as_pandas [](#__codelineno-0-13)scatter.data_as_polars` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.anywidget.value " value property writable (marimo.ui.anywidget.value)")` | The value of the widget's traits as a dictionary. **TYPE:** `Dict[str, Any]` | | `[widget](#marimo.ui.anywidget.widget " widget instance-attribute (marimo.ui.anywidget.widget)")` | The widget being wrapped. **TYPE:** `AnyWidget` | | PARAMETER | DESCRIPTION | | --- | --- | | `widget` | The widget to wrap. **TYPE:** `AnyWidget` | ### text `property` [¶](#marimo.ui.anywidget.text "Permanent link") ### value `property` `writable` [¶](#marimo.ui.anywidget.value "Permanent link") The element's current value as a plain dictionary (wire format decoded). ### widget `instance-attribute` [¶](#marimo.ui.anywidget.widget "Permanent link") ### batch [¶](#marimo.ui.anywidget.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.anywidget.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.anywidget.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.anywidget.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.anywidget.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### left [¶](#marimo.ui.anywidget.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.anywidget.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.anywidget.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Array - marimo https://docs.marimo.io/api/inputs/array/ marimo.ui.array [¶](#marimo.ui.array "Permanent link") ------------------------------------------------------ `[](#__codelineno-0-1)array( [](#__codelineno-0-2) elements: Sequence[UIElement[Any, Any]], [](#__codelineno-0-3) *, [](#__codelineno-0-4) label: str = "", [](#__codelineno-0-5) on_change: Callable[[Sequence[object]], None] [](#__codelineno-0-6) | None = None, [](#__codelineno-0-7))` Bases: `UIElement[dict[str, JSONType], Sequence[object]]` An array of UI elements. Use an array to: - create a dynamic number of UI elements at runtime - group together logically related UI elements - keep the number of global variables in your program small Access the values of the elements using the `value` attribute of the array (`array.value`). The elements in the array can be accessed using square brackets (`array[index]`) and embedded in other marimo outputs. You can also iterate over the UI elements using the `in` operator (`for element in array`). Note: The UI elements in the array are clones of the original elements: interacting with the array will _not_ update the original elements, and vice versa. Examples: A heterogeneous collection of UI elements: `[](#__codelineno-0-1)array = mo.ui.array([mo.ui.slider(1, 10), mo.ui.text(), mo.ui.date()])` Get the values of the `slider`, `text`, and `date` elements via `array.value`: `[](#__codelineno-1-1)# array.value returns a list with the values of the elements [](#__codelineno-1-2)array.value` Access and output a UI element in the array: `[](#__codelineno-2-1)mo.md(f"This is a slider: array[0]")` Some number of UI elements, determined at runtime: `[](#__codelineno-3-1)mo.ui.array([mo.ui.slider(1, 10) for _ in range random.randint(4, 8)])` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.array.value " value property writable (marimo.ui.array.value)")` | A list containing the values of the array's entries. **TYPE:** `list` | | `[elements](#marimo.ui.array.elements " elements property (marimo.ui.array.elements)")` | A list of the wrapped elements (clones of the originals). **TYPE:** `list` | | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | The UI elements to include. **TYPE:** `Sequence[UIElement]` | | `label` | A descriptive name for the array. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | `on_change` | Optional callback to run when this element's value changes. **TYPE:** `Callable[[Sequence[object]], None] | None` **DEFAULT:** `None` | ### elements `property` [¶](#marimo.ui.array.elements "Permanent link") `[](#__codelineno-0-1)elements: Sequence[UIElement[JSONType, object]]` ### text `property` [¶](#marimo.ui.array.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.array.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.array.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.array.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.array.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.array.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.array.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### hstack [¶](#marimo.ui.array.hstack "Permanent link") `[](#__codelineno-0-1)hstack(**kwargs: Any) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Stack the elements horizontally. | PARAMETER | DESCRIPTION | | --- | --- | | `**kwargs` | Additional arguments passed to `marimo.hstack`. **TYPE:** `Any` **DEFAULT:** `{}` | | RETURNS | DESCRIPTION | | --- | --- | | `Html` | HTML representation of horizontally stacked elements. **TYPE:** `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | ### left [¶](#marimo.ui.array.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.array.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.array.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | ### vstack [¶](#marimo.ui.array.vstack "Permanent link") `[](#__codelineno-0-1)vstack(**kwargs: Any) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Stack the elements vertically. | PARAMETER | DESCRIPTION | | --- | --- | | `**kwargs` | Additional arguments passed to `marimo.vstack`. **TYPE:** `Any` **DEFAULT:** `{}` | | RETURNS | DESCRIPTION | | --- | --- | | `Html` | HTML representation of vertically stacked elements. **TYPE:** `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | Batch - marimo https://docs.marimo.io/api/inputs/batch/ marimo.ui.batch [¶](#marimo.ui.batch "Permanent link") ------------------------------------------------------ `[](#__codelineno-0-1)batch( [](#__codelineno-0-2) html: [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)"), [](#__codelineno-0-3) elements: dict[str, UIElement[Any, Any]], [](#__codelineno-0-4) on_change: Callable[[dict[str, object]], None] [](#__codelineno-0-5) | None = None, [](#__codelineno-0-6))` Bases: `_batch_base` Convert an HTML object with templated text into a UI element. A `batch` is a UI element that wraps other UI elements, and is represented by custom HTML or markdown. You can create a `batch` by calling the `batch()` method on `Html` objects. Get the value of the wrapped UI elements using the `value` attribute of the batch. Examples: In the below example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and `'birthday'` (and values equal to the values of their corresponding elements). `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` To get the value of `name` and `birthday`, use: You can also instantiate this class directly: `[](#__codelineno-2-1)markdown = mo.md( [](#__codelineno-2-2) ''' [](#__codelineno-2-3) - What's your name?: {name} [](#__codelineno-2-4) - When were you born?: {birthday} [](#__codelineno-2-5) ''' [](#__codelineno-2-6)) [](#__codelineno-2-7)batch = mo.ui.batch( [](#__codelineno-2-8) markdown, {"name": mo.ui.text(), "birthday": mo.ui.date()} [](#__codelineno-2-9))` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.batch.value " value property writable (marimo.ui.batch.value)")` | A dict of the batched elements' values. **TYPE:** `dict` | | `[elements](#marimo.ui.batch.elements " elements property (marimo.ui.batch.elements)")` | A dict of the batched elements (clones of the originals). **TYPE:** `dict` | | `on_change` | Optional callback to run when this element's value changes. **TYPE:** `Callable | None` | | PARAMETER | DESCRIPTION | | --- | --- | | `html` | A templated Html object. **TYPE:** `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | | `elements` | The UI elements to interpolate into the HTML template. **TYPE:** `dict[str, UIElement]` | | `on_change` | Optional callback to run when this element's value changes. **TYPE:** `Callable[[Dict[str, object]], None] | None` **DEFAULT:** `None` | ### elements `property` [¶](#marimo.ui.batch.elements "Permanent link") `[](#__codelineno-0-1)elements: dict[str, UIElement[JSONType, object]]` ### text `property` [¶](#marimo.ui.batch.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.batch.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.batch.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.batch.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.batch.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.batch.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.batch.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### get [¶](#marimo.ui.batch.get "Permanent link") `[](#__codelineno-0-1)get(key: str, default: Any | None = None) -> Any` Get a UI element by key with an optional default value. | PARAMETER | DESCRIPTION | | --- | --- | | `key` | The key to look up in the batch. **TYPE:** `str` | | `default` | Value to return if key is not found. Defaults to None. **TYPE:** `Any | None` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | --- | --- | | `Any` | The UI element if found, otherwise the default value. **TYPE:** `Any` | ### items [¶](#marimo.ui.batch.items "Permanent link") `[](#__codelineno-0-1)items() -> ItemsView[str, UIElement[JSONType, object]]` Return a view of the batch's items (key-value pairs). | RETURNS | DESCRIPTION | | --- | --- | | `ItemsView[str, UIElement[JSONType, object]]` | ItemsView\[str, UIElement\]: A view of the batch's (key, element) pairs. | ### left [¶](#marimo.ui.batch.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.batch.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.batch.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | ### values [¶](#marimo.ui.batch.values "Permanent link") `[](#__codelineno-0-1)values() -> ValuesView[UIElement[JSONType, object]]` Return a view of the batch's values (UI elements). | RETURNS | DESCRIPTION | | --- | --- | | `ValuesView[UIElement[JSONType, object]]` | ValuesView\[UIElement\]: A view of the batch's UI elements. | Button - marimo https://docs.marimo.io/api/inputs/button/ Looking for a submit/run button? If you're looking for a button to trigger computation on click, consider using [`mo.ui.run_button`](https://docs.marimo.io/api/inputs/run_button/#marimo.ui.run_button " marimo.ui.run_button"). Source code for `examples/ui/button.py` Tip: paste this code into an empty cell, and the marimo editor will create cells for you `import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(mo): button = mo.ui.button( value=0, on_click=lambda value: value + 1, label="increment", kind="warn" ) button return (button,) @app.cell def _(button): button.value return if __name__ == "__main__": app.run()` marimo.ui.button [¶](#marimo.ui.button "Permanent link") -------------------------------------------------------- `[](#__codelineno-0-1)button( [](#__codelineno-0-2) on_click: Callable[[Any], Any] | None = None, [](#__codelineno-0-3) value: Any | None = None, [](#__codelineno-0-4) kind: Literal[ [](#__codelineno-0-5) "neutral", "success", "warn", "danger" [](#__codelineno-0-6) ] = "neutral", [](#__codelineno-0-7) disabled: bool = False, [](#__codelineno-0-8) tooltip: str | None = None, [](#__codelineno-0-9) *, [](#__codelineno-0-10) label: str = "click here", [](#__codelineno-0-11) on_change: Callable[[Any], None] | None = None, [](#__codelineno-0-12) full_width: bool = False, [](#__codelineno-0-13) keyboard_shortcut: str | None = None, [](#__codelineno-0-14))` Bases: `UIElement[Any, Any]` A button with an optional callback and optional value. Examples: `[](#__codelineno-0-1)# a button that when clicked will execute [](#__codelineno-0-2)# any cells referencing that button [](#__codelineno-0-3)button = mo.ui.button()` `[](#__codelineno-1-1)# a counter implementation [](#__codelineno-1-2)counter_button = mo.ui.button( [](#__codelineno-1-3) value=0, on_click=lambda value: value + 1, label="increment" [](#__codelineno-1-4)) [](#__codelineno-1-5)[](#__codelineno-1-6)# adding intent [](#__codelineno-1-7)delete_button = mo.ui.button( [](#__codelineno-1-8) label="Do not click", [](#__codelineno-1-9) kind="danger", [](#__codelineno-1-10))` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.button.value " value property writable (marimo.ui.button.value)")` | The value of the button. **TYPE:** `Any` | | PARAMETER | DESCRIPTION | | --- | --- | | `on_click` | A callable called on click that takes the current value of the button and returns a new value. Defaults to None. **TYPE:** `Callable[[Any], Any]` **DEFAULT:** `None` | | `value` | An initial value for the button. Defaults to None. **TYPE:** `Any` **DEFAULT:** `None` | | `kind` | Button style. Defaults to "neutral". **TYPE:** `Literal['neutral', 'success', 'warn', 'danger']` **DEFAULT:** `'neutral'` | | `disabled` | Whether the button is disabled. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `tooltip` | Tooltip text for the button. Defaults to None. **TYPE:** `str` **DEFAULT:** `None` | | `label` | Markdown label for the element. Defaults to "click here". **TYPE:** `str` **DEFAULT:** `'click here'` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Any], None]` **DEFAULT:** `None` | | `full_width` | Whether the input should take up the full width of its container. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `keyboard_shortcut` | Keyboard shortcut to trigger the button (e.g. 'Ctrl-L'). Defaults to None. **TYPE:** `str` **DEFAULT:** `None` | ### text `property` [¶](#marimo.ui.button.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.button.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.button.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.button.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.button.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.button.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.button.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### left [¶](#marimo.ui.button.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.button.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.button.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Chat - marimo https://docs.marimo.io/api/inputs/chat/ The chat UI element provides an interactive chatbot interface for conversations. It can be customized with different models, including built-in AI models from popular providers or custom functions. marimo.ui.chat [¶](#marimo.ui.chat "Permanent link") ---------------------------------------------------- `[](#__codelineno-0-1)chat( [](#__codelineno-0-2) model: Callable[ [](#__codelineno-0-3) [list[[ChatMessage](#marimo.ai.ChatMessage " marimo.ai.ChatMessage (marimo._ai._types.ChatMessage)")], [ChatModelConfig](#marimo.ai.ChatModelConfig " marimo.ai.ChatModelConfig dataclass (marimo._ai._types.ChatModelConfig)")], object [](#__codelineno-0-4) ], [](#__codelineno-0-5) *, [](#__codelineno-0-6) prompts: list[str] | None = None, [](#__codelineno-0-7) on_message: Callable[[list[[ChatMessage](#marimo.ai.ChatMessage " marimo.ai.ChatMessage (marimo._ai._types.ChatMessage)")]], None] [](#__codelineno-0-8) | None = None, [](#__codelineno-0-9) show_configuration_controls: bool = False, [](#__codelineno-0-10) config: ChatModelConfigDict | None = DEFAULT_CONFIG, [](#__codelineno-0-11) allow_attachments: bool | list[str] = False, [](#__codelineno-0-12) max_height: int | None = None, [](#__codelineno-0-13) disabled: bool = False, [](#__codelineno-0-14))` Bases: `UIElement[dict[str, Any], list[[ChatMessage](#marimo.ai.ChatMessage " marimo.ai.ChatMessage (marimo._ai._types.ChatMessage)")]]` A chatbot UI element for interactive conversations. Define a chatbot by implementing a function that takes a list of ChatMessages and optionally a config object as input, and returns the chat response. The response can be any object, including text, plots, or marimo UI elements. Examples: Using a custom model: ``[](#__codelineno-0-1)def my_rag_model(messages, config): [](#__codelineno-0-2) # Each message has a `content` attribute, as well as a `role` [](#__codelineno-0-3) # attribute ("user", "system", "assistant"); [](#__codelineno-0-4) question = messages[-1].content [](#__codelineno-0-5) docs = find_docs(question) [](#__codelineno-0-6) prompt = template(question, docs, messages) [](#__codelineno-0-7) response = query(prompt) [](#__codelineno-0-8) if is_dataset(response): [](#__codelineno-0-9) return dataset_to_chart(response) [](#__codelineno-0-10) return response [](#__codelineno-0-11) [](#__codelineno-0-12)[](#__codelineno-0-13)chat = mo.ui.chat(my_rag_model)`` Async functions and async generators are also supported: `[](#__codelineno-1-1)async def my_rag_model(messages): [](#__codelineno-1-2) return await my_async_function(messages)` Regular (sync) generators for streaming: `[](#__codelineno-2-1)def my_streaming_model(messages, config): [](#__codelineno-2-2) for chunk in process_stream(): [](#__codelineno-2-3) yield chunk # Each yield updates the UI` Async generators for streaming with async operations: `[](#__codelineno-3-1)async def my_async_streaming_model(messages, config): [](#__codelineno-3-2) async for chunk in async_process_stream(): [](#__codelineno-3-3) yield chunk # Each yield updates the UI` The last value yielded by the generator is treated as the model response. Streaming responses are automatically streamed to the frontend as they are generated. Using a built-in model: `[](#__codelineno-4-1)from pydantic_ai import Agent [](#__codelineno-4-2)[](#__codelineno-4-3)chat = mo.ui.chat( [](#__codelineno-4-4) mo.ai.llm.pydantic_ai( [](#__codelineno-4-5) Agent( [](#__codelineno-4-6) "openai:gpt-5", [](#__codelineno-4-7) system_prompt="You are a helpful assistant.", [](#__codelineno-4-8) ) [](#__codelineno-4-9) ), [](#__codelineno-4-10))` Using attachments: `[](#__codelineno-5-1)chat = mo.ui.chat( [](#__codelineno-5-2) mo.ai.llm.pydantic_ai( [](#__codelineno-5-3) Agent( [](#__codelineno-5-4) "openai:gpt-5", [](#__codelineno-5-5) system_prompt="You are a helpful assistant.", [](#__codelineno-5-6) ) [](#__codelineno-5-7) ), [](#__codelineno-5-8) allow_attachments=["image/png", "image/jpeg"], [](#__codelineno-5-9))` Custom model with Vercel AI SDK streaming (reasoning, tool calls): `[](#__codelineno-6-1)import pydantic_ai.ui.vercel_ai.response_types as vercel [](#__codelineno-6-2) [](#__codelineno-6-3)[](#__codelineno-6-4)async def custom_model(messages, config): [](#__codelineno-6-5) # Stream reasoning/thinking [](#__codelineno-6-6) yield vercel.ReasoningStartChunk(id="reasoning-1") [](#__codelineno-6-7) yield vercel.ReasoningDeltaChunk( [](#__codelineno-6-8) id="reasoning-1", delta="Let me think..." [](#__codelineno-6-9) ) [](#__codelineno-6-10) yield vercel.ReasoningEndChunk(id="reasoning-1") [](#__codelineno-6-11) [](#__codelineno-6-12) # Stream text response (can also use plain dicts) [](#__codelineno-6-13) yield {"type": "text-start", "id": "text-1"} [](#__codelineno-6-14) yield vercel.TextDeltaChunk( [](#__codelineno-6-15) id="text-1", delta="Here is my answer." [](#__codelineno-6-16) ) [](#__codelineno-6-17) yield vercel.TextEndChunk(id="text-1") [](#__codelineno-6-18) [](#__codelineno-6-19) yield vercel.FinishChunk(finish_reason="stop") [](#__codelineno-6-20) [](#__codelineno-6-21)[](#__codelineno-6-22)chat = mo.ui.chat(custom_model)` Refer to examples/ai/chat/pydantic-ai-chat.py for a complete example. | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.chat.value " value property writable (marimo.ui.chat.value)")` | The current chat history, a list of ChatMessage objects. **TYPE:** `List[[ChatMessage](#marimo.ai.ChatMessage " marimo.ai.ChatMessage (marimo._ai._types.ChatMessage)")]` | | PARAMETER | DESCRIPTION | | --- | --- | | `model` | A callable that takes in the chat history and returns a response. **TYPE:** `Callable[[List[[ChatMessage](#marimo.ai.ChatMessage " marimo.ai.ChatMessage (marimo._ai._types.ChatMessage)")], [ChatModelConfig](#marimo.ai.ChatModelConfig " marimo.ai.ChatModelConfig dataclass (marimo._ai._types.ChatModelConfig)")], object]` | | `prompts` | Optional list of initial prompts to present to the user. Defaults to None. **TYPE:** `List[str]` **DEFAULT:** `None` | | `on_message` | Optional callback function to handle new messages. Defaults to None. **TYPE:** `Callable[[List[[ChatMessage](#marimo.ai.ChatMessage " marimo.ai.ChatMessage (marimo._ai._types.ChatMessage)")]], None]` **DEFAULT:** `None` | | `show_configuration_controls` | Whether to show the configuration controls. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `config` | Optional configuration to override the default configuration. Keys include: - max\_tokens. The maximum number of tokens to generate. Defaults to 100. - temperature. Defaults to 0.5. - top\_p. Defaults to 1. - top\_k. Defaults to 40. - frequency\_penalty. Defaults to 0. - presence\_penalty. Defaults to 0. **TYPE:** `ChatModelConfigDict` **DEFAULT:** `DEFAULT_CONFIG` | | `allow_attachments` | Allow attachments. True for any attachments types, or pass a list of mime types. Defaults to False. **TYPE:** `bool | List[str]` **DEFAULT:** `False` | | `max_height` | Optional maximum height for the chat element. Defaults to None. **TYPE:** `int` **DEFAULT:** `None` | | `disabled` | Whether the chat input is disabled. When True, the user cannot type or send messages. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | ### text `property` [¶](#marimo.ui.chat.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.chat.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.chat.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.chat.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.chat.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.chat.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.chat.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### left [¶](#marimo.ui.chat.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.chat.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.chat.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Basic Usage[¶](#basic-usage "Permanent link") --------------------------------------------- Here's a simple example using a custom echo model: `[](#__codelineno-1-1)import marimo as mo [](#__codelineno-1-2)[](#__codelineno-1-3)def echo_model(messages, config): [](#__codelineno-1-4) return f"Echo: {messages[-1].content}" [](#__codelineno-1-5)[](#__codelineno-1-6)chat = mo.ui.chat(echo_model, prompts=["Hello", "How are you?"]) [](#__codelineno-1-7)chat` Here, `messages` is a list of [`ChatMessage`](#marimo.ai.ChatMessage " marimo.ai.ChatMessage") objects, which has `role` (`"user"`, `"assistant"`, or `"system"`) and `content` (the message string) attributes; `config` is a [`ChatModelConfig`](#marimo.ai.ChatModelConfig " marimo.ai.ChatModelConfig dataclass ") object with various configuration parameters, which you are free to ignore. Using Pydantic AI[¶](#using-pydantic-ai "Permanent link") --------------------------------------------------------- marimo has first class support for [pydantic-ai](https://ai.pydantic.dev/). Use the [`Agent`](https://ai.pydantic.dev/agents) class to build your chatbot and the Chat UI will display reasoning steps, tool calls and more. `[](#__codelineno-2-1)from pydantic_ai import Agent [](#__codelineno-2-2)import marimo as mo [](#__codelineno-2-3)[](#__codelineno-2-4)assistant = Agent( [](#__codelineno-2-5) "openai:gpt-5", [](#__codelineno-2-6) system_prompt="You are a helpful assistant.", [](#__codelineno-2-7)) [](#__codelineno-2-8)[](#__codelineno-2-9)chat = mo.ui.chat(mo.ai.llm.pydantic_ai(assistant)) [](#__codelineno-2-10)chat` Using a Built-in AI Model[¶](#using-a-built-in-ai-model "Permanent link") ------------------------------------------------------------------------- You can use marimo's built-in AI models, such as OpenAI's GPT: `[](#__codelineno-3-1)import marimo as mo [](#__codelineno-3-2)[](#__codelineno-3-3)chat = mo.ui.chat( [](#__codelineno-3-4) mo.ai.llm.openai( [](#__codelineno-3-5) "gpt-4", [](#__codelineno-3-6) system_message="You are a helpful assistant.", [](#__codelineno-3-7) ), [](#__codelineno-3-8) show_configuration_controls=True [](#__codelineno-3-9)) [](#__codelineno-3-10)chat` Accessing Chat History[¶](#accessing-chat-history "Permanent link") ------------------------------------------------------------------- You can access the chat history using the `value` attribute: This returns a list of [`ChatMessage`](#marimo.ai.ChatMessage " marimo.ai.ChatMessage") objects, each containing `id`, `role`, `parts` and `metadata` attributes. The `content` and `attachments` attributes are supported for basic models. Note For pydantic-ai, the messages are mapped to [Vercel UI messages](https://github.com/pydantic/pydantic-ai/blob/9aa6dd40efafd93c04c19c2ef5596a454906ca53/pydantic_ai_slim/pydantic_ai/ui/vercel_ai/request_types.py). To convert to Pydantic messages, use the adapter function. `[](#__codelineno-5-1)from pydantic_ai.ui.vercel_ai import VercelAIAdapter [](#__codelineno-5-2)[](#__codelineno-5-3)messages = VercelAIAdapter.load_messages(chat.value)` marimo.ai.ChatMessage [¶](#marimo.ai.ChatMessage "Permanent link") ------------------------------------------------------------------ Bases: `Struct` A message in a chat. ### attachments `class-attribute` `instance-attribute` [¶](#marimo.ai.ChatMessage.attachments "Permanent link") `[](#__codelineno-0-1)attachments: list[[ChatAttachment](#marimo.ai.ChatAttachment " marimo.ai.ChatAttachment dataclass (marimo._ai._types.ChatAttachment)")] | None = None` ### content `instance-attribute` [¶](#marimo.ai.ChatMessage.content "Permanent link") ### id `class-attribute` `instance-attribute` [¶](#marimo.ai.ChatMessage.id "Permanent link") ### metadata `class-attribute` `instance-attribute` [¶](#marimo.ai.ChatMessage.metadata "Permanent link") `[](#__codelineno-0-1)metadata: Any | None = None` ### parts `class-attribute` `instance-attribute` [¶](#marimo.ai.ChatMessage.parts "Permanent link") `[](#__codelineno-0-1)parts: list[ChatPart] = []` ### role `instance-attribute` [¶](#marimo.ai.ChatMessage.role "Permanent link") `[](#__codelineno-0-1)role: Literal['user', 'assistant', 'system']` ### create `classmethod` [¶](#marimo.ai.ChatMessage.create "Permanent link") `[](#__codelineno-0-1)create( [](#__codelineno-0-2) *, [](#__codelineno-0-3) role: Literal["user", "assistant", "system"], [](#__codelineno-0-4) message_id: str, [](#__codelineno-0-5) content: str | None, [](#__codelineno-0-6) parts: list[ChatPart], [](#__codelineno-0-7) part_validator_class: Any | None = None, [](#__codelineno-0-8)) -> [ChatMessage](#marimo.ai.ChatMessage " marimo.ai.ChatMessage (marimo._ai._types.ChatMessage)")` Helper method to create a ChatMessage object. If part\_validator\_class is provided, the parts will be converted to the given class. Custom Model with Additional Context[¶](#custom-model-with-additional-context "Permanent link") ----------------------------------------------------------------------------------------------- Here's an example of a custom model that uses additional context: `[](#__codelineno-6-1)import marimo as mo [](#__codelineno-6-2)[](#__codelineno-6-3)def rag_model(messages, config): [](#__codelineno-6-4) question = messages[-1].content [](#__codelineno-6-5) docs = find_relevant_docs(question) [](#__codelineno-6-6) context = "\n".join(docs) [](#__codelineno-6-7) prompt = f"Context: {context}\n\nQuestion: {question}\n\nAnswer:" [](#__codelineno-6-8) response = query_llm(prompt, config) [](#__codelineno-6-9) return response [](#__codelineno-6-10)[](#__codelineno-6-11)mo.ui.chat(rag_model)` This example demonstrates how you can implement a Retrieval-Augmented Generation (RAG) model within the chat interface. Templated Prompts[¶](#templated-prompts "Permanent link") --------------------------------------------------------- You can pass sample prompts to `mo.ui.chat` to allow users to select from a list of predefined prompts. By including a `{{var}}` in the prompt, you can dynamically insert values into the prompt; a form will be generated to allow users to fill in the variables. `[](#__codelineno-7-1)mo.ui.chat( [](#__codelineno-7-2) mo.ai.llm.openai("gpt-4o"), [](#__codelineno-7-3) prompts=[ [](#__codelineno-7-4) "What is the capital of France?", [](#__codelineno-7-5) "What is the capital of Germany?", [](#__codelineno-7-6) "What is the capital of {{country}}?", [](#__codelineno-7-7) ], [](#__codelineno-7-8))` Including Attachments[¶](#including-attachments "Permanent link") ----------------------------------------------------------------- You can allow users to upload attachments to their messages by passing an `allow_attachments` parameter to `mo.ui.chat`. `[](#__codelineno-8-1)mo.ui.chat( [](#__codelineno-8-2) rag_model, [](#__codelineno-8-3) allow_attachments=["image/png", "image/jpeg"], [](#__codelineno-8-4) # or True for any attachment type [](#__codelineno-8-5) # allow_attachments=True, [](#__codelineno-8-6))` Streaming Responses[¶](#streaming-responses "Permanent link") ------------------------------------------------------------- Chatbots can stream responses in real-time, creating a more interactive experience similar to ChatGPT where you see the response appear word-by-word as it's generated. Responses from built-in models (OpenAI, Anthropic, Google, Groq, Bedrock) are streamed by default. ### How Streaming Works[¶](#how-streaming-works "Permanent link") marimo uses **delta-based streaming**, which follows the industry-standard pattern used by OpenAI, Anthropic, and other AI providers. Your generator function should yield **individual chunks** (deltas) of new content, which marimo automatically accumulates and displays progressively. ### With Custom Models[¶](#with-custom-models "Permanent link") For custom models, you can use either regular (sync) or async generator functions that yield delta chunks: **Sync generator (simpler):** `[](#__codelineno-9-1)import marimo as mo [](#__codelineno-9-2)import time [](#__codelineno-9-3)[](#__codelineno-9-4)def streaming_model(messages, config): [](#__codelineno-9-5) """Stream responses word by word.""" [](#__codelineno-9-6) response = "This response will appear word by word!" [](#__codelineno-9-7) words = response.split() [](#__codelineno-9-8) [](#__codelineno-9-9) for word in words: [](#__codelineno-9-10) yield word + " " # Yield delta chunks [](#__codelineno-9-11) time.sleep(0.1) # Simulate processing delay [](#__codelineno-9-12)[](#__codelineno-9-13)chat = mo.ui.chat(streaming_model) [](#__codelineno-9-14)chat` **Async generator (for async operations):** `[](#__codelineno-10-1)import marimo as mo [](#__codelineno-10-2)import asyncio [](#__codelineno-10-3)[](#__codelineno-10-4)async def async_streaming_model(messages, config): [](#__codelineno-10-5) """Stream responses word by word asynchronously.""" [](#__codelineno-10-6) response = "This response will appear word by word!" [](#__codelineno-10-7) words = response.split() [](#__codelineno-10-8) [](#__codelineno-10-9) for word in words: [](#__codelineno-10-10) yield word + " " # Yield delta chunks [](#__codelineno-10-11) await asyncio.sleep(0.1) # Async processing delay [](#__codelineno-10-12)[](#__codelineno-10-13)chat = mo.ui.chat(async_streaming_model) [](#__codelineno-10-14)chat` Each `yield` sends a new chunk (delta) to marimo, which accumulates and displays the progressively building response in real-time. Delta vs Accumulated **Yield deltas, not accumulated text.** Each yield should be **new content only**: ✅ **Correct (delta mode):** `[](#__codelineno-11-1)yield "Hello" [](#__codelineno-11-2)yield " " [](#__codelineno-11-3)yield "world" [](#__codelineno-11-4)# Result: "Hello world"` ❌ **Incorrect (accumulated mode, deprecated):** `[](#__codelineno-12-1)yield "Hello" [](#__codelineno-12-2)yield "Hello " [](#__codelineno-12-3)yield "Hello world" [](#__codelineno-12-4)# Inefficient: sends duplicate content` Delta mode is more efficient (reduces bandwidth by ~99% for long responses) and aligns with standard streaming APIs. Built-in Models[¶](#built-in-models "Permanent link") ----------------------------------------------------- marimo provides several built-in AI models that you can use with the chat UI element. ### Pydantic AI[¶](#pydantic-ai "Permanent link") `[](#__codelineno-13-1)import marimo as mo [](#__codelineno-13-2)from pydantic_ai import Agent [](#__codelineno-13-3)[](#__codelineno-13-4)assistant = Agent( [](#__codelineno-13-5) "openai:gpt-5", [](#__codelineno-13-6) system_prompt="You are a helpful assistant.", [](#__codelineno-13-7)) [](#__codelineno-13-8)[](#__codelineno-13-9)mo.ui.chat(mo.ai.llm.pydantic_ai(assistant))` marimo.ai.llm.pydantic\_ai [¶](#marimo.ai.llm.pydantic_ai "Permanent link") --------------------------------------------------------------------------- `[](#__codelineno-0-1)pydantic_ai(agent: Agent[Any, Any])` Bases: `ChatModel` [Pydantic AI](https://ai.pydantic.dev/) ChatModel | PARAMETER | DESCRIPTION | | --- | --- | | `agent` | A pydantic\_ai Agent instance. [See docs](https://ai.pydantic.dev/agents/) **TYPE:** `Agent[Any, Any]` | Example `[](#__codelineno-0-1)from pydantic_ai import Agent [](#__codelineno-0-2)[](#__codelineno-0-3)agent = Agent( [](#__codelineno-0-4) model="gpt-5", system_prompt="You are a helpful assistant." [](#__codelineno-0-5)) [](#__codelineno-0-6)chatbot = mo.ui.chat( [](#__codelineno-0-7) mo.ai.llm.pydantic_ai(agent), [](#__codelineno-0-8) prompts=["What is the capital of France?", "What is marimo?"], [](#__codelineno-0-9)) [](#__codelineno-0-10)chatbot` ### agent `instance-attribute` [¶](#marimo.ai.llm.pydantic_ai.agent "Permanent link") ### OpenAI[¶](#openai "Permanent link") `[](#__codelineno-14-1)import marimo as mo [](#__codelineno-14-2)[](#__codelineno-14-3)mo.ui.chat( [](#__codelineno-14-4) mo.ai.llm.openai( [](#__codelineno-14-5) "gpt-4o", [](#__codelineno-14-6) system_message="You are a helpful assistant.", [](#__codelineno-14-7) api_key="sk-proj-...", [](#__codelineno-14-8) ), [](#__codelineno-14-9) show_configuration_controls=True [](#__codelineno-14-10))` marimo.ai.llm.openai [¶](#marimo.ai.llm.openai "Permanent link") ---------------------------------------------------------------- `[](#__codelineno-0-1)openai( [](#__codelineno-0-2) model: str, [](#__codelineno-0-3) *, [](#__codelineno-0-4) system_message: str = DEFAULT_SYSTEM_MESSAGE, [](#__codelineno-0-5) api_key: str | None = None, [](#__codelineno-0-6) base_url: str | None = None, [](#__codelineno-0-7))` Bases: `ChatModel` OpenAI ChatModel | PARAMETER | DESCRIPTION | | --- | --- | | `model` | The model to use. Can be found on the [OpenAI models page](https://platform.openai.com/docs/models) **TYPE:** `str` | | `system_message` | The system message to use **TYPE:** `str` **DEFAULT:** `DEFAULT_SYSTEM_MESSAGE` | | `api_key` | The API key to use. If not provided, the API key will be retrieved from the OPENAI\_API\_KEY environment variable or the user's config. **TYPE:** `str | None` **DEFAULT:** `None` | | `base_url` | The base URL to use **TYPE:** `str | None` **DEFAULT:** `None` | ### api\_key `instance-attribute` [¶](#marimo.ai.llm.openai.api_key "Permanent link") ### base\_url `instance-attribute` [¶](#marimo.ai.llm.openai.base_url "Permanent link") ### model `instance-attribute` [¶](#marimo.ai.llm.openai.model "Permanent link") ### system\_message `instance-attribute` [¶](#marimo.ai.llm.openai.system_message "Permanent link") `[](#__codelineno-0-1)system_message = system_message` ### Anthropic[¶](#anthropic "Permanent link") `[](#__codelineno-15-1)import marimo as mo [](#__codelineno-15-2)[](#__codelineno-15-3)mo.ui.chat( [](#__codelineno-15-4) mo.ai.llm.anthropic( [](#__codelineno-15-5) "claude-3-5-sonnet-20240620", [](#__codelineno-15-6) system_message="You are a helpful assistant.", [](#__codelineno-15-7) api_key="sk-ant-...", [](#__codelineno-15-8) ), [](#__codelineno-15-9) show_configuration_controls=True [](#__codelineno-15-10))` marimo.ai.llm.anthropic [¶](#marimo.ai.llm.anthropic "Permanent link") ---------------------------------------------------------------------- `[](#__codelineno-0-1)anthropic( [](#__codelineno-0-2) model: str, [](#__codelineno-0-3) *, [](#__codelineno-0-4) system_message: str = DEFAULT_SYSTEM_MESSAGE, [](#__codelineno-0-5) api_key: str | None = None, [](#__codelineno-0-6) base_url: str | None = None, [](#__codelineno-0-7))` Bases: `ChatModel` Anthropic ChatModel | PARAMETER | DESCRIPTION | | --- | --- | | `model` | The model to use. Can be found on the [Anthropic models page](https://docs.anthropic.com/en/docs/about-claude/models) **TYPE:** `str` | | `system_message` | The system message to use **TYPE:** `str` **DEFAULT:** `DEFAULT_SYSTEM_MESSAGE` | | `api_key` | The API key to use. If not provided, the API key will be retrieved from the ANTHROPIC\_API\_KEY environment variable or the user's config. **TYPE:** `str | None` **DEFAULT:** `None` | | `base_url` | The base URL to use **TYPE:** `str | None` **DEFAULT:** `None` | ### api\_key `instance-attribute` [¶](#marimo.ai.llm.anthropic.api_key "Permanent link") ### base\_url `instance-attribute` [¶](#marimo.ai.llm.anthropic.base_url "Permanent link") ### model `instance-attribute` [¶](#marimo.ai.llm.anthropic.model "Permanent link") ### system\_message `instance-attribute` [¶](#marimo.ai.llm.anthropic.system_message "Permanent link") `[](#__codelineno-0-1)system_message = system_message` ### supports\_temperature [¶](#marimo.ai.llm.anthropic.supports_temperature "Permanent link") `[](#__codelineno-0-1)supports_temperature(model: str) -> bool` ### Google AI[¶](#google-ai "Permanent link") `[](#__codelineno-16-1)import marimo as mo [](#__codelineno-16-2)[](#__codelineno-16-3)mo.ui.chat( [](#__codelineno-16-4) mo.ai.llm.google( [](#__codelineno-16-5) "gemini-1.5-pro-latest", [](#__codelineno-16-6) system_message="You are a helpful assistant.", [](#__codelineno-16-7) api_key="AI..", [](#__codelineno-16-8) ), [](#__codelineno-16-9) show_configuration_controls=True [](#__codelineno-16-10))` marimo.ai.llm.google [¶](#marimo.ai.llm.google "Permanent link") ---------------------------------------------------------------- `[](#__codelineno-0-1)google( [](#__codelineno-0-2) model: str, [](#__codelineno-0-3) *, [](#__codelineno-0-4) system_message: str = DEFAULT_SYSTEM_MESSAGE, [](#__codelineno-0-5) api_key: str | None = None, [](#__codelineno-0-6))` Bases: `ChatModel` Google AI ChatModel | PARAMETER | DESCRIPTION | | --- | --- | | `model` | The model to use. Can be found on the [Gemini models page](https://ai.google.dev/gemini-api/docs/models/gemini) **TYPE:** `str` | | `system_message` | The system message to use **TYPE:** `str` **DEFAULT:** `DEFAULT_SYSTEM_MESSAGE` | | `api_key` | The API key to use. If not provided, the API key will be retrieved from the GOOGLE\_AI\_API\_KEY environment variable or the user's config. **TYPE:** `str | None` **DEFAULT:** `None` | ### api\_key `instance-attribute` [¶](#marimo.ai.llm.google.api_key "Permanent link") ### model `instance-attribute` [¶](#marimo.ai.llm.google.model "Permanent link") ### system\_message `instance-attribute` [¶](#marimo.ai.llm.google.system_message "Permanent link") `[](#__codelineno-0-1)system_message = system_message` ### Groq[¶](#groq "Permanent link") `[](#__codelineno-17-1)import marimo as mo [](#__codelineno-17-2)[](#__codelineno-17-3)mo.ui.chat( [](#__codelineno-17-4) mo.ai.llm.groq( [](#__codelineno-17-5) "llama-3.1-70b-versatile", [](#__codelineno-17-6) system_message="You are a helpful assistant.", [](#__codelineno-17-7) api_key="gsk-...", [](#__codelineno-17-8) ), [](#__codelineno-17-9) show_configuration_controls=True [](#__codelineno-17-10))` marimo.ai.llm.groq [¶](#marimo.ai.llm.groq "Permanent link") ------------------------------------------------------------ `[](#__codelineno-0-1)groq( [](#__codelineno-0-2) model: str, [](#__codelineno-0-3) *, [](#__codelineno-0-4) system_message: str = DEFAULT_SYSTEM_MESSAGE, [](#__codelineno-0-5) api_key: str | None = None, [](#__codelineno-0-6) base_url: str | None = None, [](#__codelineno-0-7))` Bases: `ChatModel` Groq ChatModel | PARAMETER | DESCRIPTION | | --- | --- | | `model` | The model to use. Can be found on the [Groq models page](https://console.groq.com/docs/models) **TYPE:** `str` | | `system_message` | The system message to use **TYPE:** `str` **DEFAULT:** `DEFAULT_SYSTEM_MESSAGE` | | `api_key` | The API key to use. If not provided, the API key will be retrieved from the GROQ\_API\_KEY environment variable or the user's config. **TYPE:** `str | None` **DEFAULT:** `None` | | `base_url` | The base URL to use **TYPE:** `str | None` **DEFAULT:** `None` | ### api\_key `instance-attribute` [¶](#marimo.ai.llm.groq.api_key "Permanent link") ### base\_url `instance-attribute` [¶](#marimo.ai.llm.groq.base_url "Permanent link") ### model `instance-attribute` [¶](#marimo.ai.llm.groq.model "Permanent link") ### system\_message `instance-attribute` [¶](#marimo.ai.llm.groq.system_message "Permanent link") `[](#__codelineno-0-1)system_message = system_message` Types[¶](#types "Permanent link") --------------------------------- Chatbots can be implemented with a function that receives a list of [`ChatMessage`](#marimo.ai.ChatMessage " marimo.ai.ChatMessage") objects and a [`ChatModelConfig`](#marimo.ai.ChatModelConfig " marimo.ai.ChatModelConfig dataclass "). marimo.ai.ChatMessage [¶](#marimo.ai.ChatMessage "Permanent link") ------------------------------------------------------------------ Bases: `Struct` A message in a chat. ### attachments `class-attribute` `instance-attribute` [¶](#marimo.ai.ChatMessage.attachments "Permanent link") `[](#__codelineno-0-1)attachments: list[[ChatAttachment](#marimo.ai.ChatAttachment " marimo.ai.ChatAttachment dataclass (marimo._ai._types.ChatAttachment)")] | None = None` ### content `instance-attribute` [¶](#marimo.ai.ChatMessage.content "Permanent link") ### id `class-attribute` `instance-attribute` [¶](#marimo.ai.ChatMessage.id "Permanent link") ### metadata `class-attribute` `instance-attribute` [¶](#marimo.ai.ChatMessage.metadata "Permanent link") `[](#__codelineno-0-1)metadata: Any | None = None` ### parts `class-attribute` `instance-attribute` [¶](#marimo.ai.ChatMessage.parts "Permanent link") `[](#__codelineno-0-1)parts: list[ChatPart] = []` ### role `instance-attribute` [¶](#marimo.ai.ChatMessage.role "Permanent link") `[](#__codelineno-0-1)role: Literal['user', 'assistant', 'system']` ### create `classmethod` [¶](#marimo.ai.ChatMessage.create "Permanent link") `[](#__codelineno-0-1)create( [](#__codelineno-0-2) *, [](#__codelineno-0-3) role: Literal["user", "assistant", "system"], [](#__codelineno-0-4) message_id: str, [](#__codelineno-0-5) content: str | None, [](#__codelineno-0-6) parts: list[ChatPart], [](#__codelineno-0-7) part_validator_class: Any | None = None, [](#__codelineno-0-8)) -> [ChatMessage](#marimo.ai.ChatMessage " marimo.ai.ChatMessage (marimo._ai._types.ChatMessage)")` Helper method to create a ChatMessage object. If part\_validator\_class is provided, the parts will be converted to the given class. marimo.ai.ChatModelConfig `dataclass` [¶](#marimo.ai.ChatModelConfig "Permanent link") -------------------------------------------------------------------------------------- `[](#__codelineno-0-1)ChatModelConfig( [](#__codelineno-0-2) max_tokens: int | None = None, [](#__codelineno-0-3) temperature: float | None = None, [](#__codelineno-0-4) top_p: float | None = None, [](#__codelineno-0-5) top_k: int | None = None, [](#__codelineno-0-6) frequency_penalty: float | None = None, [](#__codelineno-0-7) presence_penalty: float | None = None, [](#__codelineno-0-8))` ### frequency\_penalty `class-attribute` `instance-attribute` [¶](#marimo.ai.ChatModelConfig.frequency_penalty "Permanent link") `[](#__codelineno-0-1)frequency_penalty: float | None = None` ### max\_tokens `class-attribute` `instance-attribute` [¶](#marimo.ai.ChatModelConfig.max_tokens "Permanent link") `[](#__codelineno-0-1)max_tokens: int | None = None` ### presence\_penalty `class-attribute` `instance-attribute` [¶](#marimo.ai.ChatModelConfig.presence_penalty "Permanent link") `[](#__codelineno-0-1)presence_penalty: float | None = None` ### temperature `class-attribute` `instance-attribute` [¶](#marimo.ai.ChatModelConfig.temperature "Permanent link") `[](#__codelineno-0-1)temperature: float | None = None` ### top\_k `class-attribute` `instance-attribute` [¶](#marimo.ai.ChatModelConfig.top_k "Permanent link") ### top\_p `class-attribute` `instance-attribute` [¶](#marimo.ai.ChatModelConfig.top_p "Permanent link") `[](#__codelineno-0-1)top_p: float | None = None` [`mo.ui.chat`](#marimo.ui.chat " marimo.ui.chat") can be instantiated with an initial configuration with a dictionary conforming to the config. `ChatMessage`s can also include attachments. marimo.ai.ChatAttachment `dataclass` [¶](#marimo.ai.ChatAttachment "Permanent link") ------------------------------------------------------------------------------------ `[](#__codelineno-0-1)ChatAttachment( [](#__codelineno-0-2) url: str, [](#__codelineno-0-3) name: str = "attachment", [](#__codelineno-0-4) content_type: str | None = None, [](#__codelineno-0-5))` ### content\_type `class-attribute` `instance-attribute` [¶](#marimo.ai.ChatAttachment.content_type "Permanent link") `[](#__codelineno-0-1)content_type: str | None = None` ### name `class-attribute` `instance-attribute` [¶](#marimo.ai.ChatAttachment.name "Permanent link") ### url `instance-attribute` [¶](#marimo.ai.ChatAttachment.url "Permanent link") Supported Model Providers[¶](#supported-model-providers "Permanent link") ------------------------------------------------------------------------- We support any OpenAI-compatible endpoint. If you want any specific provider added explicitly (ones that don't abide by the standard OpenAI API format), you can file a [feature request](https://github.com/marimo-team/marimo/issues/new?template=feature_request.yaml). Normally, overriding the `base_url` parameter should work. Here are some examples: CerebrasGroqxAI `[](#__codelineno-18-1)chatbot = mo.ui.chat( [](#__codelineno-18-2) mo.ai.llm.openai( [](#__codelineno-18-3) model="llama3.1-8b", [](#__codelineno-18-4) api_key="csk-...", # insert your key here [](#__codelineno-18-5) base_url="https://api.cerebras.ai/v1/", [](#__codelineno-18-6) ), [](#__codelineno-18-7)) [](#__codelineno-18-8)chatbot` `[](#__codelineno-19-1)chatbot = mo.ui.chat( [](#__codelineno-19-2) mo.ai.llm.openai( [](#__codelineno-19-3) model="llama-3.1-70b-versatile", [](#__codelineno-19-4) api_key="gsk_...", # insert your key here [](#__codelineno-19-5) base_url="https://api.groq.com/openai/v1/", [](#__codelineno-19-6) ), [](#__codelineno-19-7)) [](#__codelineno-19-8)chatbot` `[](#__codelineno-20-1)chatbot = mo.ui.chat( [](#__codelineno-20-2) mo.ai.llm.openai( [](#__codelineno-20-3) model="grok-beta", [](#__codelineno-20-4) api_key=key, # insert your key here [](#__codelineno-20-5) base_url="https://api.x.ai/v1", [](#__codelineno-20-6) ), [](#__codelineno-20-7)) [](#__codelineno-20-8)chatbot` Note We have added examples for GROQ and Cerebras. These providers offer free API keys and are great for trying out Llama models (from Meta). You can sign up on their platforms and integrate with various AI integrations in marimo easily. For more information, refer to the [AI completion documentation in marimo](https://docs.marimo.io/guides/editor_features/ai_completion/). Checkbox - marimo https://docs.marimo.io/api/inputs/checkbox/ marimo.ui.checkbox [¶](#marimo.ui.checkbox "Permanent link") ------------------------------------------------------------ `[](#__codelineno-0-1)checkbox( [](#__codelineno-0-2) value: bool = False, [](#__codelineno-0-3) *, [](#__codelineno-0-4) label: str = "", [](#__codelineno-0-5) disabled: bool = False, [](#__codelineno-0-6) on_change: Callable[[bool], None] | None = None, [](#__codelineno-0-7))` Bases: `UIElement[bool, bool]` A boolean checkbox. Examples: `[](#__codelineno-0-1)checkbox = mo.ui.checkbox()` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.checkbox.value " value property writable (marimo.ui.checkbox.value)")` | A boolean, True if checked. **TYPE:** `bool` | | PARAMETER | DESCRIPTION | | --- | --- | | `value` | Default value, True or False. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `label` | Markdown label for the element. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[bool], None]` **DEFAULT:** `None` | | `disabled` | Whether the checkbox is disabled. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | ### text `property` [¶](#marimo.ui.checkbox.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.checkbox.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.checkbox.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.checkbox.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.checkbox.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.checkbox.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.checkbox.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### left [¶](#marimo.ui.checkbox.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.checkbox.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.checkbox.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Code Editor - marimo https://docs.marimo.io/api/inputs/code_editor/ Source code for `examples/ui/code_editor.py` Tip: paste this code into an empty cell, and the marimo editor will create cells for you `import marimo __generated_with = "0.19.7" app = marimo.App(width="medium") @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(mo): initial_code = """# implement foo below def foo(): ... """ editor = mo.ui.code_editor(value=initial_code, language="python") editor return (editor,) @app.cell def _(editor): editor.value return @app.cell def _(mo): copy_editor = mo.ui.code_editor( value="let a = 'b';", language="javascript", show_copy_button=False, ) copy_editor return if __name__ == "__main__": app.run()` marimo.ui.code\_editor [¶](#marimo.ui.code_editor "Permanent link") ------------------------------------------------------------------- `[](#__codelineno-0-1)code_editor( [](#__codelineno-0-2) value: str = "", [](#__codelineno-0-3) language: str = "python", [](#__codelineno-0-4) placeholder: str = "", [](#__codelineno-0-5) theme: Literal["light", "dark"] | None = None, [](#__codelineno-0-6) disabled: bool = False, [](#__codelineno-0-7) min_height: int | None = None, [](#__codelineno-0-8) max_height: int | None = None, [](#__codelineno-0-9) show_copy_button: bool = True, [](#__codelineno-0-10) debounce: bool | int = False, [](#__codelineno-0-11) *, [](#__codelineno-0-12) label: str = "", [](#__codelineno-0-13) on_change: Callable[[str], None] | None = None, [](#__codelineno-0-14))` Bases: `UIElement[str, str]` A code editor. Examples: `[](#__codelineno-0-1)code_editor = mo.ui.code_editor()` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.code_editor.value " value property writable (marimo.ui.code_editor.value)")` | A string of the code editor contents. **TYPE:** `str` | | PARAMETER | DESCRIPTION | | --- | --- | | `value` | Initial value of the code editor. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | `language` | Language of the code editor. Most major languages are supported, including "sql", "javascript", "typescript", "html", "css", "c", "cpp", "rust", and more. Defaults to "python". **TYPE:** `str` **DEFAULT:** `'python'` | | `placeholder` | Placeholder text to display when the code editor is empty. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | `theme` | Theme of the code editor. Defaults to the editor's default. **TYPE:** `Literal['light', 'dark']` **DEFAULT:** `None` | | `disabled` | Whether the input is disabled. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `min_height` | Minimum height of the code editor in pixels. Defaults to None. **TYPE:** `int` **DEFAULT:** `None` | | `max_height` | Maximum height of the code editor in pixels. Defaults to None. **TYPE:** `int` **DEFAULT:** `None` | | `label` | Markdown label for the element. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[str], None]` **DEFAULT:** `None` | | `show_copy_button` | Whether to show a button to copy the code to the clipboard. Defaults to True. **TYPE:** `bool` **DEFAULT:** `True` | | `debounce` | Whether the input is debounced. If number, debounce by that many milliseconds. If True, then value is only emitted when the input loses focus. Defaults to False. **TYPE:** `bool | int` **DEFAULT:** `False` | ### text `property` [¶](#marimo.ui.code_editor.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.code_editor.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.code_editor.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.code_editor.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.code_editor.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.code_editor.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.code_editor.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### left [¶](#marimo.ui.code_editor.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.code_editor.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.code_editor.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Data Editor - marimo https://docs.marimo.io/api/inputs/data_editor/ Source code for `examples/ui/data_editor.py` Tip: paste this code into an empty cell, and the marimo editor will create cells for you `# /// script # requires-python = ">=3.12" # dependencies = [ # "polars==1.39.3", # "vega-datasets==0.9.0", # ] # /// import marimo __generated_with = "0.19.7" app = marimo.App(width="medium") @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(): import os return (os,) @app.cell def _(): DATA_FILE = "data.csv" return (DATA_FILE,) @app.cell def _(DATA_FILE, mo, os): import polars as pl if not os.path.exists(DATA_FILE): from vega_datasets import data data.cars().to_csv(DATA_FILE) editor = mo.ui.data_editor(pl.read_csv(DATA_FILE)).form(bordered=False) editor return (editor,) @app.cell(hide_code=True) def _(mo): mo.md(""" The following cell writes the updated dataframe to disk when the submit button is clicked. """) return @app.cell def _(DATA_FILE, editor, mo): mo.stop(editor.value is None, mo.md("Submit your changes.")) editor.value.write_csv(DATA_FILE) return if __name__ == "__main__": app.run()` marimo.ui.data\_editor [¶](#marimo.ui.data_editor "Permanent link") ------------------------------------------------------------------- `[](#__codelineno-0-1)data_editor( [](#__codelineno-0-2) data: RowOrientedData [](#__codelineno-0-3) | ColumnOrientedData [](#__codelineno-0-4) | IntoDataFrame, [](#__codelineno-0-5) *, [](#__codelineno-0-6) label: str = "", [](#__codelineno-0-7) on_change: Callable[ [](#__codelineno-0-8) [ [](#__codelineno-0-9) Union[ [](#__codelineno-0-10) RowOrientedData, [](#__codelineno-0-11) ColumnOrientedData, [](#__codelineno-0-12) IntoDataFrame, [](#__codelineno-0-13) ] [](#__codelineno-0-14) ], [](#__codelineno-0-15) None, [](#__codelineno-0-16) ] [](#__codelineno-0-17) | None = None, [](#__codelineno-0-18) editable_columns: list[str] | Literal["all"] = "all", [](#__codelineno-0-19) column_sizing_mode: Literal["auto", "fit"] [](#__codelineno-0-20) | None = None, [](#__codelineno-0-21) pagination: bool | None = None, [](#__codelineno-0-22) page_size: int | None = None, [](#__codelineno-0-23))` Bases: `UIElement[DataEdits, RowOrientedData | ColumnOrientedData | IntoDataFrame]` A data editor component for editing tabular data. This component is experimental and intentionally limited in features, if you have any feature requests, please file an issue at [https://github.com/marimo-team/marimo/issues](https://github.com/marimo-team/marimo/issues). The data can be supplied as: 1. a Pandas, Polars, or Pyarrow DataFrame 2. a list of dicts, with one dict for each row, keyed by column names 3. a dict of lists, with each list representing a column Examples: Create a data editor from a Pandas dataframe: `[](#__codelineno-0-1)import pandas as pd [](#__codelineno-0-2)[](#__codelineno-0-3)df = pd.DataFrame({"A": [1, 2, 3], "B": ["a", "b", "c"]}) [](#__codelineno-0-4)editor = mo.ui.data_editor(data=df, label="Edit Data")` Create a data editor from a list of dicts: `[](#__codelineno-1-1)data = [{"A": 1, "B": "a"}, {"A": 2, "B": "a"}, {"A": 3, "B": "c"}] [](#__codelineno-1-2)editor = mo.ui.data_editor(data=data, label="Edit Data")` Create a data editor from a dict of lists: `[](#__codelineno-2-1)data = {"A": [1, 2, 3], "B": ["a", "b", "c"]} [](#__codelineno-2-2)editor = mo.ui.data_editor(data=data, label="Edit Data")` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.data_editor.value " value property writable (marimo.ui.data_editor.value)")` | The current state of the edited data. **TYPE:** `RowOrientedData | ColumnOrientedData | IntoDataFrame` | | `[data](#marimo.ui.data_editor.data " data property (marimo.ui.data_editor.data)")` | The original data passed to the editor. **TYPE:** `RowOrientedData | ColumnOrientedData | IntoDataFrame` | | PARAMETER | DESCRIPTION | | --- | --- | | `data` | The data to be edited. Can be a Pandas dataframe, a list of dicts, or a dict of lists. **TYPE:** `RowOrientedData | ColumnOrientedData | IntoDataFrame` | | `label` | Markdown label for the element. **TYPE:** `str` **DEFAULT:** `''` | | `on_change` | Optional callback to run when this element's value changes. **TYPE:** `Callable | None` **DEFAULT:** `None` | | `editable_columns` | A list of column names to be editable. If "all", all columns are editable. Pass an empty list to make all columns read-only. Defaults to "all". **TYPE:** `list[str] | Literal['all']` **DEFAULT:** `'all'` | Deprecated pagination (bool): Whether to enable pagination. page\_size (int): The number of rows to display per page. column\_sizing\_mode (Literal\["auto", "fit"\]): The column sizing mode for the table. ### data `property` [¶](#marimo.ui.data_editor.data "Permanent link") `[](#__codelineno-0-1)data: RowOrientedData | ColumnOrientedData | IntoDataFrame` ### text `property` [¶](#marimo.ui.data_editor.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.data_editor.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.data_editor.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.data_editor.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.data_editor.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.data_editor.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.data_editor.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### left [¶](#marimo.ui.data_editor.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.data_editor.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.data_editor.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Data Explorer - marimo https://docs.marimo.io/api/inputs/data_explorer/ The data explorer UI element outputs a visual editor explore your data via plotting and intelligent recommendations. You can incrementally build your "main" plot by adding different encodings: x-axis, y-axis, color, size, and shape. As you build your plot, the UI element will suggest further plots by intelligently "exploding" an additional encoding derived from your base plot. Pandas Required In order to use the dataframe UI element, you must have the `pandas` package installed. You can install it with `pip install pandas`. To set an initial configuration, you can pass keyword arguments to `mo.ui.data_explorer`. For example, to start with `sepal_length` on the x-axis, `sepal_width` on the y-axis, and `species` as the color encoding: marimo.ui.data\_explorer [¶](#marimo.ui.data_explorer "Permanent link") ----------------------------------------------------------------------- `[](#__codelineno-0-1)data_explorer( [](#__codelineno-0-2) df: IntoDataFrame, [](#__codelineno-0-3) on_change: Callable[[dict[str, Any]], None] [](#__codelineno-0-4) | None = None, [](#__codelineno-0-5) x: str | None = None, [](#__codelineno-0-6) y: str | None = None, [](#__codelineno-0-7) row: str | None = None, [](#__codelineno-0-8) column: str | None = None, [](#__codelineno-0-9) color: str | None = None, [](#__codelineno-0-10) size: str | None = None, [](#__codelineno-0-11) shape: str | None = None, [](#__codelineno-0-12))` Bases: `UIElement[dict[str, Any], dict[str, Any]]` Quickly explore a DataFrame with automatically suggested visualizations. Examples: `[](#__codelineno-0-1)mo.ui.data_explorer(data) [](#__codelineno-0-2)mo.ui.data_explorer(data, x="col_A", y="col_B", color="col_C")` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.data_explorer.value " value property writable (marimo.ui.data_explorer.value)")` | The chart specification, which may include initial selections if provided via keyword arguments. **TYPE:** `Dict[str, Any]` | | PARAMETER | DESCRIPTION | | --- | --- | | `df` | The DataFrame to visualize. **TYPE:** `IntoDataFrame` | | `on_change` | Optional callback to run when this element's value changes. **TYPE:** `Callable[[dict[str, Any]], None]` **DEFAULT:** `None` | | `x` | Initial column for the x-axis. Defaults to None. **TYPE:** `str | None` **DEFAULT:** `None` | | `y` | Initial column for the y-axis. Defaults to None. **TYPE:** `str | None` **DEFAULT:** `None` | | `row` | Initial column for the row dimension. Defaults to None. **TYPE:** `str | None` **DEFAULT:** `None` | | `column` | Initial column for the column dimension. Defaults to None. **TYPE:** `str | None` **DEFAULT:** `None` | | `color` | Initial column for the color encoding. Defaults to None. **TYPE:** `str | None` **DEFAULT:** `None` | | `size` | Initial column for the size encoding. Defaults to None. **TYPE:** `str | None` **DEFAULT:** `None` | | `shape` | Initial column for the shape encoding. Defaults to None. **TYPE:** `str | None` **DEFAULT:** `None` | ### text `property` [¶](#marimo.ui.data_explorer.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.data_explorer.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.data_explorer.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.data_explorer.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.data_explorer.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.data_explorer.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.data_explorer.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### left [¶](#marimo.ui.data_explorer.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.data_explorer.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.data_explorer.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | DataFrame - marimo https://docs.marimo.io/api/inputs/dataframe/ The dataframe UI element outputs a visual editor to apply "transforms" to a dataframe, such as filtering rows, applying group-bys and aggregations, and more. The transformed dataframe is shown below the transform editor. The UI output also includes the generated Python used to generate the resulting dataframe, which you can copy paste into a cell. You can programmatically access the resulting dataframe by accessing the element's `.value` attribute. Pandas or Polars Required In order to use the dataframe UI element, you must have the `pandas` or `polars` package installed. You can install it with `pip install pandas` or `pip install polars`. Supported transforms are: * Filter Rows * Select Columns * Rename Column * Column Conversion * Sort Column * Group By * Aggregate * Sample Rows * Shuffle Rows * Explode Columns * Expand Dict * Unique * Pivot marimo.ui.dataframe [¶](#marimo.ui.dataframe "Permanent link") -------------------------------------------------------------- `[](#__codelineno-0-1)dataframe( [](#__codelineno-0-2) df: DataFrameType, [](#__codelineno-0-3) on_change: Callable[[DataFrameType], None] [](#__codelineno-0-4) | None = None, [](#__codelineno-0-5) page_size: int | None = 5, [](#__codelineno-0-6) limit: int | None = None, [](#__codelineno-0-7) show_download: bool = True, [](#__codelineno-0-8) *, [](#__codelineno-0-9) format_mapping: FormatMapping | None = None, [](#__codelineno-0-10) download_csv_encoding: str | None = None, [](#__codelineno-0-11) download_csv_separator: str | None = None, [](#__codelineno-0-12) download_json_ensure_ascii: bool = True, [](#__codelineno-0-13) lazy: bool | None = None, [](#__codelineno-0-14))` Bases: `UIElement[dict[str, Any], DataFrameType]` Run transformations on a DataFrame or series. Currently supports Pandas, Polars, Ibis, Pyarrow, and DuckDB. Examples: `[](#__codelineno-0-1)dataframe = mo.ui.dataframe(data)` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.dataframe.value " value property writable (marimo.ui.dataframe.value)")` | The transformed DataFrame or series. **TYPE:** `DataFrameType` | | PARAMETER | DESCRIPTION | | --- | --- | | `df` | The DataFrame or series to transform. **TYPE:** `DataFrameType` | | `page_size` | The number of rows to show in the table. Defaults to 5. **TYPE:** `int | None` **DEFAULT:** `5` | | `limit` | The number of items to load into memory, in case the data is remote and lazily fetched. This is likely true for SQL-backed dataframes via Ibis. **TYPE:** `int | None` **DEFAULT:** `None` | | `show_download` | Whether to show the download button. Defaults to True. **TYPE:** `bool` **DEFAULT:** `True` | | `format_mapping` | A mapping from column names to formatting strings or functions. **TYPE:** `Dict[str, str | Callable[..., Any]] | None` **DEFAULT:** `None` | | `download_csv_encoding` | Encoding used when downloading CSV. Defaults to the runtime config value (or "utf-8" if not configured). Set to "utf-8-sig" to include BOM for Excel. **TYPE:** `str | None` **DEFAULT:** `None` | | `download_csv_separator` | Separator used in CSV downloads. Defaults to ",". **TYPE:** `str | None` **DEFAULT:** `None` | | `download_json_ensure_ascii` | Whether to escape non-ASCII characters in JSON downloads. Defaults to True. **TYPE:** `bool` **DEFAULT:** `True` | | `on_change` | Optional callback to run when this element's value changes. **TYPE:** `Callable[[DataFrameType], None] | None` **DEFAULT:** `None` | | `lazy` | When lazy is True, an 'Apply' button will be shown to apply transformations. Defaults to None where lazy is inferred from the dataframe and row count. **TYPE:** `bool | None` **DEFAULT:** `None` | ### text `property` [¶](#marimo.ui.dataframe.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.dataframe.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.dataframe.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.dataframe.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.dataframe.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.dataframe.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.dataframe.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### left [¶](#marimo.ui.dataframe.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.dataframe.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.dataframe.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Dictionary - marimo https://docs.marimo.io/api/inputs/dictionary/ marimo.ui.dictionary [¶](#marimo.ui.dictionary "Permanent link") ---------------------------------------------------------------- `[](#__codelineno-0-1)dictionary( [](#__codelineno-0-2) elements: dict[str, UIElement[Any, Any]], [](#__codelineno-0-3) *, [](#__codelineno-0-4) label: str = "", [](#__codelineno-0-5) on_change: Callable[[dict[str, object]], None] [](#__codelineno-0-6) | None = None, [](#__codelineno-0-7))` Bases: `_batch_base` A dictionary of UI elements. Use a dictionary to: - create a set of UI elements at runtime - group together logically related UI elements - keep the number of global variables in your program small Access the values of the elements using the `value` attribute of the dictionary. The elements in the dictionary can be accessed using square brackets (`dictionary[key]`) and embedded in other marimo outputs. You can also iterate over the UI elements using the same syntax used for Python dicts. Note The UI elements in the dictionary are clones of the original elements: interacting with the dictionary will _not_ update the original elements, and vice versa. The main reason to use `mo.ui.dictionary` is for reactive execution — when you interact with an element in a `mo.ui.dictionary`, all cells that reference the `mo.ui.dictionary` run automatically, just like all other ui elements. When you use a regular dictionary, you don't get this reactivity. Examples: A heterogeneous collection of UI elements: `[](#__codelineno-0-1)d = mo.ui.dictionary( [](#__codelineno-0-2) { [](#__codelineno-0-3) "slider": mo.ui.slider(1, 10), [](#__codelineno-0-4) "text": mo.ui.text(), [](#__codelineno-0-5) "date": mo.ui.date(), [](#__codelineno-0-6) } [](#__codelineno-0-7))` Get the values of the `slider`, `text`, and `date` elements via `d.value`: `[](#__codelineno-1-1)# d.value returns a dict with keys "slider", "text", "date" [](#__codelineno-1-2)d.value` Access and output a UI element in the array: `[](#__codelineno-2-1)mo.md(f"This is a slider: {d['slider']}")` Some number of UI elements, determined at runtime: `[](#__codelineno-3-1)mo.ui.dictionary( [](#__codelineno-3-2) { [](#__codelineno-3-3) f"option {i}": mo.ui.slider(1, 10) [](#__codelineno-3-4) for i in range(random.randint(4, 8)) [](#__codelineno-3-5) } [](#__codelineno-3-6))` Quick layouts of UI elements: ``[](#__codelineno-4-1)mo.ui.dictionary( [](#__codelineno-4-2) { [](#__codelineno-4-3) f"option {i}": mo.ui.slider(1, 10) [](#__codelineno-4-4) for i in range(random.randint(4, 8)) [](#__codelineno-4-5) } [](#__codelineno-4-6)).vstack() # Can also use `hstack`, `callout`, `center`, etc.`` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.dictionary.value " value property writable (marimo.ui.dictionary.value)")` | A dict holding the values of the UI elements, keyed by their names. **TYPE:** `dict` | | `[elements](#marimo.ui.dictionary.elements " elements property (marimo.ui.dictionary.elements)")` | A dict of the wrapped elements (clones of the originals). **TYPE:** `dict` | | `on_change` | Optional callback to run when this element's value changes. **TYPE:** `Callable[[dict[str, object]], None] | None` | | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | A dict mapping names to UI elements to include. **TYPE:** `dict[str, UIElement[Any, Any]]` | | `label` | A descriptive name for the dictionary. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | `on_change` | Optional callback to run when this element's value changes. **TYPE:** `Callable[[dict[str, object]], None]` **DEFAULT:** `None` | ### elements `property` [¶](#marimo.ui.dictionary.elements "Permanent link") `[](#__codelineno-0-1)elements: dict[str, UIElement[JSONType, object]]` ### text `property` [¶](#marimo.ui.dictionary.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.dictionary.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.dictionary.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.dictionary.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.dictionary.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.dictionary.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.dictionary.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### get [¶](#marimo.ui.dictionary.get "Permanent link") `[](#__codelineno-0-1)get(key: str, default: Any | None = None) -> Any` Get a UI element by key with an optional default value. | PARAMETER | DESCRIPTION | | --- | --- | | `key` | The key to look up in the batch. **TYPE:** `str` | | `default` | Value to return if key is not found. Defaults to None. **TYPE:** `Any | None` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | --- | --- | | `Any` | The UI element if found, otherwise the default value. **TYPE:** `Any` | ### hstack [¶](#marimo.ui.dictionary.hstack "Permanent link") `[](#__codelineno-0-1)hstack(**kwargs: Any) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Stack the elements horizontally. For kwargs, see `marimo.hstack`. ### items [¶](#marimo.ui.dictionary.items "Permanent link") `[](#__codelineno-0-1)items() -> ItemsView[str, UIElement[JSONType, object]]` Return a view of the batch's items (key-value pairs). | RETURNS | DESCRIPTION | | --- | --- | | `ItemsView[str, UIElement[JSONType, object]]` | ItemsView\[str, UIElement\]: A view of the batch's (key, element) pairs. | ### left [¶](#marimo.ui.dictionary.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.dictionary.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.dictionary.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | ### values [¶](#marimo.ui.dictionary.values "Permanent link") `[](#__codelineno-0-1)values() -> ValuesView[UIElement[JSONType, object]]` Return a view of the batch's values (UI elements). | RETURNS | DESCRIPTION | | --- | --- | | `ValuesView[UIElement[JSONType, object]]` | ValuesView\[UIElement\]: A view of the batch's UI elements. | ### vstack [¶](#marimo.ui.dictionary.vstack "Permanent link") `[](#__codelineno-0-1)vstack(**kwargs: Any) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Stack the elements vertically. For kwargs, see `marimo.vstack`. Dates - marimo https://docs.marimo.io/api/inputs/dates/ Single date[¶](#single-date "Permanent link") --------------------------------------------- marimo.ui.date [¶](#marimo.ui.date "Permanent link") ---------------------------------------------------- `[](#__codelineno-0-1)date( [](#__codelineno-0-2) start: date | str | None = None, [](#__codelineno-0-3) stop: date | str | None = None, [](#__codelineno-0-4) value: date | str | None = None, [](#__codelineno-0-5) *, [](#__codelineno-0-6) label: str = "", [](#__codelineno-0-7) on_change: Callable[[date], None] | None = None, [](#__codelineno-0-8) full_width: bool = False, [](#__codelineno-0-9) disabled: bool = False, [](#__codelineno-0-10))` Bases: `UIElement[str, date]` A date picker with an optional start and stop date. Examples: `[](#__codelineno-0-1)# initialize the date picker at a given date [](#__codelineno-0-2)date = mo.ui.date(value="2022-01-01")` `[](#__codelineno-1-1)# when value is omitted, date picker initializes with today's date [](#__codelineno-1-2)date = mo.ui.date()` `[](#__codelineno-2-1)# create a date picker with bounds [](#__codelineno-2-2)date = mo.ui.date( [](#__codelineno-2-3) value="2022-06-01", [](#__codelineno-2-4) start="2022-01-01", [](#__codelineno-2-5) stop="2022-12-31", [](#__codelineno-2-6))` Or from a dataframe series: `[](#__codelineno-3-1)date = mo.ui.date.from_series(df["column_name"])` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.date.value " value property writable (marimo.ui.date.value)")` | A str (YYYY-MM-DD) or `datetime.date` object of the chosen date. **TYPE:** `str | date` | | `[start](#marimo.ui.date.start " start property (marimo.ui.date.start)")` | The start date. **TYPE:** `date` | | `[stop](#marimo.ui.date.stop " stop property (marimo.ui.date.stop)")` | The stop date. **TYPE:** `date` | | PARAMETER | DESCRIPTION | | --- | --- | | `start` | Minimum date selectable. If None, defaults to 01-01-0001. **TYPE:** `date | str` **DEFAULT:** `None` | | `stop` | Maximum date selectable. If None, defaults to 12-31-9999. **TYPE:** `date | str` **DEFAULT:** `None` | | `value` | Default date. If None and start and stop are None, defaults to the current day. If None and start is not None, defaults to start. If None and stop is not None, defaults to stop. **TYPE:** `date | str` **DEFAULT:** `None` | | `label` | Markdown label for the element. **TYPE:** `str` **DEFAULT:** `''` | | `on_change` | Optional callback to run when this element's value changes. **TYPE:** `Callable[[date], None]` **DEFAULT:** `None` | | `full_width` | Whether the input should take up the full width of its container. **TYPE:** `bool` **DEFAULT:** `False` | | `disabled` | Whether the input should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | ### DATE\_FORMAT `class-attribute` `instance-attribute` [¶](#marimo.ui.date.DATE_FORMAT "Permanent link") ### start `property` [¶](#marimo.ui.date.start "Permanent link") Get the minimum selectable date. | RETURNS | DESCRIPTION | | --- | --- | | `date` | datetime.date: The start date, which is either the user-specified minimum date or 01-01-0001 if no start date was specified. | ### stop `property` [¶](#marimo.ui.date.stop "Permanent link") Get the maximum selectable date. | RETURNS | DESCRIPTION | | --- | --- | | `date` | datetime.date: The stop date, which is either the user-specified maximum date or 12-31-9999 if no stop date was specified. | ### text `property` [¶](#marimo.ui.date.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.date.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.date.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.date.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.date.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.date.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.date.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### from\_series `staticmethod` [¶](#marimo.ui.date.from_series "Permanent link") `[](#__codelineno-0-1)from_series(series: DataFrameSeries, **kwargs: Any) -> [date](#marimo.ui.date " marimo.ui.date (marimo._plugins.ui._impl.dates.date)")` Create a date picker from a dataframe series. | PARAMETER | DESCRIPTION | | --- | --- | | `series` | A pandas Series containing datetime values. **TYPE:** `DataFrameSeries` | | `**kwargs` | Additional keyword arguments passed to the date picker constructor. Supported arguments: start, stop, label, and any other date picker parameters. **TYPE:** `Any` **DEFAULT:** `{}` | | RETURNS | DESCRIPTION | | --- | --- | | `date` | A date picker initialized with the series' min and max dates as bounds. **TYPE:** `[date](#marimo.ui.date " marimo.ui.date (marimo._plugins.ui._impl.dates.date)")` | ### left [¶](#marimo.ui.date.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.date.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.date.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | :members: Date and time[¶](#date-and-time "Permanent link") ------------------------------------------------- `[](#__codelineno-1-1) @app.cell [](#__codelineno-1-2) def __(): [](#__codelineno-1-3) datetime = mo.ui.datetime(label="Start Date") [](#__codelineno-1-4) return [](#__codelineno-1-5) [](#__codelineno-1-6) @app.cell [](#__codelineno-1-7) def __(): [](#__codelineno-1-8) mo.hstack([datetime, mo.md(f"Has value: {datetime.value}")]) [](#__codelineno-1-9) return` marimo.ui.datetime [¶](#marimo.ui.datetime "Permanent link") ------------------------------------------------------------ `[](#__codelineno-0-1)datetime( [](#__codelineno-0-2) start: datetime | str | None = None, [](#__codelineno-0-3) stop: datetime | str | None = None, [](#__codelineno-0-4) value: datetime | str | None = None, [](#__codelineno-0-5) *, [](#__codelineno-0-6) precision: Literal[ [](#__codelineno-0-7) "hour", "minute", "second" [](#__codelineno-0-8) ] = "minute", [](#__codelineno-0-9) label: str | None = None, [](#__codelineno-0-10) on_change: Callable[[Optional[datetime]], None] [](#__codelineno-0-11) | None = None, [](#__codelineno-0-12) full_width: bool = False, [](#__codelineno-0-13) disabled: bool = False, [](#__codelineno-0-14))` Bases: `UIElement[str | None, datetime | None]` A datetime picker over an interval. Examples: `[](#__codelineno-0-1)datetime_picker = mo.ui.datetime( [](#__codelineno-0-2) start=dt.datetime(2023, 1, 1), [](#__codelineno-0-3) stop=dt.datetime(2023, 12, 31, 23, 59, 59), [](#__codelineno-0-4))` Or from a dataframe series: `[](#__codelineno-1-1)datetime_picker = mo.ui.datetime.from_series(df["datetime_column"])` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.datetime.value " value property writable (marimo.ui.datetime.value)")` | The selected datetime, possibly None. **TYPE:** `datetime` | | `[start](#marimo.ui.datetime.start " start property (marimo.ui.datetime.start)")` | The minimum selectable datetime. **TYPE:** `datetime` | | `[stop](#marimo.ui.datetime.stop " stop property (marimo.ui.datetime.stop)")` | The maximum selectable datetime. **TYPE:** `datetime` | | PARAMETER | DESCRIPTION | | --- | --- | | `start` | The minimum selectable datetime. Defaults to minimum datetime. **TYPE:** `datetime | str` **DEFAULT:** `None` | | `stop` | The maximum selectable datetime. Defaults to maximum datetime. **TYPE:** `datetime | str` **DEFAULT:** `None` | | `value` | Default value. **TYPE:** `datetime | str` **DEFAULT:** `None` | | `precision` | The precision of the datetime picker. Defaults to "minute". **TYPE:** `Literal['hour', 'minute', 'second']` **DEFAULT:** `'minute'` | | `label` | Markdown label for the element. **TYPE:** `str` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. **TYPE:** `Callable[[Optional[datetime]], None]` **DEFAULT:** `None` | | `full_width` | Whether the input should take up the full width of its container. **TYPE:** `bool` **DEFAULT:** `False` | | `disabled` | Whether the input should be disabled. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | ### DATETIME\_FORMAT `class-attribute` `instance-attribute` [¶](#marimo.ui.datetime.DATETIME_FORMAT "Permanent link") `[](#__codelineno-0-1)DATETIME_FORMAT: Final[str] = '%Y-%m-%dT%H:%M:%S'` ### start `property` [¶](#marimo.ui.datetime.start "Permanent link") Get the minimum selectable datetime. | RETURNS | DESCRIPTION | | --- | --- | | `datetime` | datetime.datetime: The start datetime, which is either the user-specified minimum datetime or datetime.min if no start datetime was specified. | ### stop `property` [¶](#marimo.ui.datetime.stop "Permanent link") Get the maximum selectable datetime. | RETURNS | DESCRIPTION | | --- | --- | | `datetime` | datetime.datetime: The stop datetime, which is either the user-specified maximum datetime or datetime.max if no stop datetime was specified. | ### text `property` [¶](#marimo.ui.datetime.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.datetime.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.datetime.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.datetime.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.datetime.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.datetime.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.datetime.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### from\_series `staticmethod` [¶](#marimo.ui.datetime.from_series "Permanent link") `[](#__codelineno-0-1)from_series( [](#__codelineno-0-2) series: DataFrameSeries, **kwargs: Any [](#__codelineno-0-3)) -> [datetime](#marimo.ui.datetime " marimo.ui.datetime (marimo._plugins.ui._impl.dates.datetime)")` Create a datetime picker from a dataframe series. | PARAMETER | DESCRIPTION | | --- | --- | | `series` | A pandas Series containing datetime values. **TYPE:** `DataFrameSeries` | | `**kwargs` | Additional keyword arguments passed to the datetime picker constructor. Supported arguments: start, stop, label, and any other datetime picker parameters. **TYPE:** `Any` **DEFAULT:** `{}` | | RETURNS | DESCRIPTION | | --- | --- | | `datetime` | A datetime picker initialized with the series' min and max datetimes as bounds. **TYPE:** `[datetime](#marimo.ui.datetime " marimo.ui.datetime (marimo._plugins.ui._impl.dates.datetime)")` | ### left [¶](#marimo.ui.datetime.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.datetime.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.datetime.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | :members: Date range[¶](#date-range "Permanent link") ------------------------------------------- marimo.ui.date\_range [¶](#marimo.ui.date_range "Permanent link") ----------------------------------------------------------------- `[](#__codelineno-0-1)date_range( [](#__codelineno-0-2) start: date | str | None = None, [](#__codelineno-0-3) stop: date | str | None = None, [](#__codelineno-0-4) value: tuple[date, date] [](#__codelineno-0-5) | tuple[str, str] [](#__codelineno-0-6) | None = None, [](#__codelineno-0-7) *, [](#__codelineno-0-8) label: str | None = None, [](#__codelineno-0-9) on_change: Callable[[tuple[date, date]], None] [](#__codelineno-0-10) | None = None, [](#__codelineno-0-11) full_width: bool = False, [](#__codelineno-0-12) disabled: bool = False, [](#__codelineno-0-13))` Bases: `UIElement[tuple[str, str], tuple[date, date]]` A date range picker over an interval. Examples: `[](#__codelineno-0-1)date_range = mo.ui.date_range( [](#__codelineno-0-2) start=dt.date(2023, 1, 1), stop=dt.date(2023, 12, 31) [](#__codelineno-0-3))` Or from a dataframe series: `[](#__codelineno-1-1)date_range = mo.ui.date_range.from_series(df["date_column"])` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.date_range.value " value property writable (marimo.ui.date_range.value)")` | A tuple of (start\_date, end\_date) representing the selected range. **TYPE:** `Tuple[date, date]` | | `[start](#marimo.ui.date_range.start " start property (marimo.ui.date_range.start)")` | The minimum selectable date. **TYPE:** `date` | | `[stop](#marimo.ui.date_range.stop " stop property (marimo.ui.date_range.stop)")` | The maximum selectable date. **TYPE:** `date` | | PARAMETER | DESCRIPTION | | --- | --- | | `start` | Minimum date selectable. If None, defaults to 01-01-0001. **TYPE:** `date | str` **DEFAULT:** `None` | | `stop` | Maximum date selectable. If None, defaults to 12-31-9999. **TYPE:** `date | str` **DEFAULT:** `None` | | `value` | Default value as (start\_date, end\_date). If None, defaults to (start, stop) if provided, otherwise today's date for both. **TYPE:** `Tuple[date | str, date | str]` **DEFAULT:** `None` | | `label` | Markdown label for the element. **TYPE:** `str` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. **TYPE:** `Callable[[Tuple[date, date]], None]` **DEFAULT:** `None` | | `full_width` | Whether the input should take up the full width of its container. **TYPE:** `bool` **DEFAULT:** `False` | | `disabled` | Whether the input should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | ### DATEFORMAT `class-attribute` `instance-attribute` [¶](#marimo.ui.date_range.DATEFORMAT "Permanent link") `[](#__codelineno-0-1)DATEFORMAT: Final[str] = '%Y-%m-%d'` ### start `property` [¶](#marimo.ui.date_range.start "Permanent link") Get the minimum selectable date. | RETURNS | DESCRIPTION | | --- | --- | | `date` | datetime.date: The start date, which is either the user-specified minimum date or 01-01-0001 if no start date was specified. | ### stop `property` [¶](#marimo.ui.date_range.stop "Permanent link") Get the maximum selectable date. | RETURNS | DESCRIPTION | | --- | --- | | `date` | datetime.date: The stop date, which is either the user-specified maximum date or 12-31-9999 if no stop date was specified. | ### text `property` [¶](#marimo.ui.date_range.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.date_range.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.date_range.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.date_range.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.date_range.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.date_range.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.date_range.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### from\_series `staticmethod` [¶](#marimo.ui.date_range.from_series "Permanent link") `[](#__codelineno-0-1)from_series( [](#__codelineno-0-2) series: DataFrameSeries, **kwargs: Any [](#__codelineno-0-3)) -> [date_range](#marimo.ui.date_range " marimo.ui.date_range (marimo._plugins.ui._impl.dates.date_range)")` Create a date range picker from a dataframe series. | PARAMETER | DESCRIPTION | | --- | --- | | `series` | A pandas Series containing datetime values. **TYPE:** `DataFrameSeries` | | `**kwargs` | Additional keyword arguments passed to the date range picker constructor. Supported arguments: start, stop, label, and any other date range picker parameters. **TYPE:** `Any` **DEFAULT:** `{}` | | RETURNS | DESCRIPTION | | --- | --- | | `date_range` | A date range picker initialized with the series' min and max dates as bounds. **TYPE:** `[date_range](#marimo.ui.date_range " marimo.ui.date_range (marimo._plugins.ui._impl.dates.date_range)")` | ### left [¶](#marimo.ui.date_range.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.date_range.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.date_range.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | :members: Dropdown - marimo https://docs.marimo.io/api/inputs/dropdown/ marimo.ui.dropdown [¶](#marimo.ui.dropdown "Permanent link") ------------------------------------------------------------ `[](#__codelineno-0-1)dropdown( [](#__codelineno-0-2) options: Sequence[Any] | dict[str, Any], [](#__codelineno-0-3) value: Any | None = None, [](#__codelineno-0-4) allow_select_none: bool | None = None, [](#__codelineno-0-5) searchable: bool = False, [](#__codelineno-0-6) *, [](#__codelineno-0-7) label: str = "", [](#__codelineno-0-8) on_change: Callable[[Any], None] | None = None, [](#__codelineno-0-9) full_width: bool = False, [](#__codelineno-0-10))` Bases: `UIElement[list[str], Any]` A dropdown selector. Examples: `[](#__codelineno-0-1)dropdown = mo.ui.dropdown( [](#__codelineno-0-2) options=["a", "b", "c"], value="a", label="choose one" [](#__codelineno-0-3)) [](#__codelineno-0-4)[](#__codelineno-0-5)# With search functionality [](#__codelineno-0-6)dropdown = mo.ui.dropdown( [](#__codelineno-0-7) options=["a", "b", "c"], [](#__codelineno-0-8) value="a", [](#__codelineno-0-9) label="choose one", [](#__codelineno-0-10) searchable=True, [](#__codelineno-0-11))` `[](#__codelineno-1-1)dropdown = mo.ui.dropdown( [](#__codelineno-1-2) options={"one": 1, "two": 2, "three": 3}, [](#__codelineno-1-3) value="one", [](#__codelineno-1-4) label="pick a number", [](#__codelineno-1-5))` Or from a dataframe series: `[](#__codelineno-2-1)dropdown = mo.ui.dropdown.from_series(df["column_name"])` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.dropdown.value " value property writable (marimo.ui.dropdown.value)")` | The selected value, or None if no selection. **TYPE:** `Any` | | `[options](#marimo.ui.dropdown.options " options instance-attribute (marimo.ui.dropdown.options)")` | A dict mapping option name to option value. **TYPE:** `dict` | | `[selected_key](#marimo.ui.dropdown.selected_key " selected_key property (marimo.ui.dropdown.selected_key)")` | The selected option's key, or None if no selection. **TYPE:** `str` | | PARAMETER | DESCRIPTION | | --- | --- | | `options` | Sequence of options, or dict mapping option name to option value. If the options are not strings, they will be converted to strings when displayed in the dropdown. **TYPE:** `Sequence[Any] | dict[str, Any]` | | `value` | Default option name. Defaults to None. **TYPE:** `str` **DEFAULT:** `None` | | `allow_select_none` | Whether to include special option ("--") for a None value; when None, defaults to True when value is None. Defaults to None. **TYPE:** `bool` **DEFAULT:** `None` | | `searchable` | Whether to enable search functionality. Defaults to False. If the number of options is greater than 1000, this will be set to True, automatically. **TYPE:** `bool` **DEFAULT:** `False` | | `label` | Markdown label for the element. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Any], None]` **DEFAULT:** `None` | | `full_width` | Whether the input should take up the full width of its container. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | ### options `instance-attribute` [¶](#marimo.ui.dropdown.options "Permanent link") ### selected\_key `property` [¶](#marimo.ui.dropdown.selected_key "Permanent link") The selected option's key, or `None` if no selection. ### text `property` [¶](#marimo.ui.dropdown.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.dropdown.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.dropdown.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.dropdown.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.dropdown.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.dropdown.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.dropdown.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### from\_series `staticmethod` [¶](#marimo.ui.dropdown.from_series "Permanent link") `[](#__codelineno-0-1)from_series( [](#__codelineno-0-2) series: DataFrameSeries, **kwargs: Any [](#__codelineno-0-3)) -> [dropdown](#marimo.ui.dropdown " marimo.ui.dropdown (marimo._plugins.ui._impl.input.dropdown)")` Create a dropdown from a dataframe series. ### left [¶](#marimo.ui.dropdown.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.dropdown.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.dropdown.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | File - marimo https://docs.marimo.io/api/inputs/file/ marimo.ui.file [¶](#marimo.ui.file "Permanent link") ---------------------------------------------------- `[](#__codelineno-0-1)file( [](#__codelineno-0-2) filetypes: Sequence[str] | None = None, [](#__codelineno-0-3) multiple: bool = False, [](#__codelineno-0-4) kind: Literal["button", "area"] = "button", [](#__codelineno-0-5) *, [](#__codelineno-0-6) max_size: int = 100000000, [](#__codelineno-0-7) label: str = "", [](#__codelineno-0-8) on_change: Callable[[Sequence[FileUploadResults]], None] [](#__codelineno-0-9) | None = None, [](#__codelineno-0-10))` Bases: `UIElement[list[tuple[str, str]], Sequence[FileUploadResults]]` A button or drag-and-drop area to upload a file. Once a file is uploaded, the UI element's value is a list of namedtuples (name, contents), where name is the filename and contents is the contents of the file. Alternatively, use the methods name(index: int = 0) and contents(index: int = 0) to retrieve the name or contents of the file at a specified index. Use the kind argument to switch between a button and a drag-and-drop area. The maximum file size is 100MB. Examples: Uploading a single file: `[](#__codelineno-1-1)# In another cell, access the uploaded file's name [](#__codelineno-1-2)f.value[0].name [](#__codelineno-1-3)# or [](#__codelineno-1-4)f.name() [](#__codelineno-1-5)[](#__codelineno-1-6)# access the uploaded file's contents [](#__codelineno-1-7)f.value[0].contents [](#__codelineno-1-8)# or [](#__codelineno-1-9)f.contents()` Uploading multiple files, accepting only .png and .jpg extensions: `[](#__codelineno-2-1)f = mo.ui.file(filetypes=[".png", ".jpg"], multiple=True) [](#__codelineno-2-2)f` `[](#__codelineno-3-1)# In another cell, access an uploaded file's name [](#__codelineno-3-2)f.value[index].name [](#__codelineno-3-3)# or [](#__codelineno-3-4)f.name(index) [](#__codelineno-3-5)[](#__codelineno-3-6)# access the uploaded file's contents [](#__codelineno-3-7)f.value[index].contents [](#__codelineno-3-8)# or [](#__codelineno-3-9)f.contents(index)` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.file.value " value property writable (marimo.ui.file.value)")` | A sequence of FileUploadResults, which have string name and bytes contents fields. **TYPE:** `Sequence[FileUploadResults]` | | METHOD | DESCRIPTION | | --- | --- | | `[name](#marimo.ui.file.name " name (marimo.ui.file.name)")` | int = 0) -> Optional\[str\]: Get the name of the uploaded file at index. | | `[contents](#marimo.ui.file.contents " contents (marimo.ui.file.contents)")` | int = 0) -> Optional\[bytes\]: Get the contents of the uploaded file at index. | | PARAMETER | DESCRIPTION | | --- | --- | | `filetypes` | The file types accepted; for example, filetypes=\[".png", ".jpg"\]. If None, all files are accepted. In addition to extensions, you may provide "audio/_", "video/_", or "image/\*" to accept any audio, video, or image file. Defaults to None. **TYPE:** `Sequence[str]` **DEFAULT:** `None` | | `multiple` | If True, allow the user to upload multiple files. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `kind` | Type of upload interface. Defaults to "button". **TYPE:** `Literal['button', 'area']` **DEFAULT:** `'button'` | | `label` | Markdown label for the element. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Sequence[FileUploadResults]], None]` **DEFAULT:** `None` | | `max_size` | The maximum size of the file to upload (in bytes). Defaults to 100MB. **TYPE:** `int` **DEFAULT:** `100000000` | ### text `property` [¶](#marimo.ui.file.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.file.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.file.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.file.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.file.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### contents [¶](#marimo.ui.file.contents "Permanent link") `[](#__codelineno-0-1)contents(index: int = 0) -> bytes | None` Get file contents at index. | PARAMETER | DESCRIPTION | | --- | --- | | `index` | Index of the file to get the contents from. Defaults to 0. **TYPE:** `int` **DEFAULT:** `0` | | RETURNS | DESCRIPTION | | --- | --- | | `bytes | None` | Optional\[bytes\]: The contents of the file at the specified index, or None if index is out of range. | ### form [¶](#marimo.ui.file.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.file.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### left [¶](#marimo.ui.file.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### name [¶](#marimo.ui.file.name "Permanent link") `[](#__codelineno-0-1)name(index: int = 0) -> str | None` Get file name at index. | PARAMETER | DESCRIPTION | | --- | --- | | `index` | Index of the file to get the name from. Defaults to 0. **TYPE:** `int` **DEFAULT:** `0` | | RETURNS | DESCRIPTION | | --- | --- | | `str | None` | Optional\[str\]: The name of the file at the specified index, or None if index is out of range. | ### right [¶](#marimo.ui.file.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.file.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | File Browser - marimo https://docs.marimo.io/api/inputs/file_browser/ marimo.ui.file\_browser [¶](#marimo.ui.file_browser "Permanent link") --------------------------------------------------------------------- `[](#__codelineno-0-1)file_browser( [](#__codelineno-0-2) initial_path: str | Path = "", [](#__codelineno-0-3) filetypes: Sequence[str] | None = None, [](#__codelineno-0-4) selection_mode: Literal["file", "directory"] = "file", [](#__codelineno-0-5) multiple: bool = True, [](#__codelineno-0-6) restrict_navigation: bool = False, [](#__codelineno-0-7) *, [](#__codelineno-0-8) limit: int | None = None, [](#__codelineno-0-9) label: str = "", [](#__codelineno-0-10) on_change: Callable[ [](#__codelineno-0-11) [Sequence[FileBrowserFileInfo]], None [](#__codelineno-0-12) ] [](#__codelineno-0-13) | None = None, [](#__codelineno-0-14) ignore_empty_dirs: bool = False, [](#__codelineno-0-15))` Bases: `UIElement[list[TypedFileBrowserFileInfo], Sequence[FileBrowserFileInfo]]` File browser for browsing and selecting server-side files. This element supports local files, S3, GCS, and Azure. Examples: Selecting multiple files: `[](#__codelineno-0-1)file_browser = mo.ui.file_browser( [](#__codelineno-0-2) initial_path=Path("path/to/dir"), multiple=True [](#__codelineno-0-3)) [](#__codelineno-0-4)[](#__codelineno-0-5)# Access the selected file path(s): [](#__codelineno-0-6)file_browser.path(index=0) # returns a Path object [](#__codelineno-0-7)[](#__codelineno-0-8)# Get name of selected file(s) [](#__codelineno-0-9)file_browser.name(index=0)` Connecting to an S3 (or GCS, Azure) bucket: `[](#__codelineno-1-1)from cloudpathlib import S3Path [](#__codelineno-1-2)[](#__codelineno-1-3)file_browser = mo.ui.file_browser( [](#__codelineno-1-4) initial_path=S3Path("s3://my-bucket/folder/") [](#__codelineno-1-5)) [](#__codelineno-1-6)[](#__codelineno-1-7)# Access the selected file path(s): [](#__codelineno-1-8)file_browser.path(index=0) # returns a S3Path object [](#__codelineno-1-9)[](#__codelineno-1-10)# Read the contents of the selected file(s): [](#__codelineno-1-11)file_browser.path(index=0).read_text()` Using with client credentials: `[](#__codelineno-2-1)from cloudpathlib import GSClient, GSPath [](#__codelineno-2-2)[](#__codelineno-2-3)# Create a client with credentials [](#__codelineno-2-4)gs_client = GSClient("storage_credentials.json", project="my-project") [](#__codelineno-2-5)[](#__codelineno-2-6)# Create a path with the client [](#__codelineno-2-7)cloudpath = GSPath("gs://my-bucket/folder", client=gs_client) [](#__codelineno-2-8)[](#__codelineno-2-9)# Use the path with file_browser [](#__codelineno-2-10)file_browser = mo.ui.file_browser(initial_path=cloudpath)` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.file_browser.value " value property writable (marimo.ui.file_browser.value)")` | A sequence of file paths representing selected files. **TYPE:** `Sequence[FileInfo]` | | PARAMETER | DESCRIPTION | | --- | --- | | `initial_path` | Starting directory. Defaults to current working directory. If a string, it will be interpreted as a local path. If a Path, it will be interpreted as a local path. If a CloudPath (from cloudpathlib), such as S3Path, GCSPath, or AzurePath, files will be loaded from the respective cloud storage bucket. If a CloudPath with a client is provided, that client will be used for all operations. **TYPE:** `str | Path | AnyPath` **DEFAULT:** `''` | | `filetypes` | The file types to display in each directory; for example, filetypes=\[".txt", ".csv"\]. If None, all files are displayed. Defaults to None. **TYPE:** `Sequence[str]` **DEFAULT:** `None` | | `selection_mode` | Either "file" or "directory". Defaults to "file". **TYPE:** `Literal['file', 'directory']` **DEFAULT:** `'file'` | | `multiple` | If True, allow the user to select multiple files. Defaults to True. **TYPE:** `bool` **DEFAULT:** `True` | | `restrict_navigation` | If True, prevent the user from navigating any level above the given path. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `ignore_empty_dirs` | If True, hide directories that contain no files (recursively). Directories are scanned up to 100 levels deep to prevent stack overflow from deeply nested structures. Directory symlinks are skipped during traversal to prevent infinite loops. Filetype filtering is applied recursively and is case-insensitive. This may impact performance for large directory trees. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `limit` | Maximum number of files to display. If None (default), automatically chooses 50 for cloud storage (S3, GCS, Azure) or 10000 for local filesystems. Set explicitly to override defaults. **TYPE:** `int` **DEFAULT:** `None` | | `label` | Markdown label for the element. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Sequence[FileInfo]], None]` **DEFAULT:** `None` | ### text `property` [¶](#marimo.ui.file_browser.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.file_browser.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.file_browser.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.file_browser.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.file_browser.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.file_browser.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.file_browser.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### left [¶](#marimo.ui.file_browser.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### name [¶](#marimo.ui.file_browser.name "Permanent link") `[](#__codelineno-0-1)name(index: int = 0) -> str | None` Get file name at index. | PARAMETER | DESCRIPTION | | --- | --- | | `index` | Index of the file to get the name from. Defaults to 0. **TYPE:** `int` **DEFAULT:** `0` | | RETURNS | DESCRIPTION | | --- | --- | | `str | None` | Optional\[str\]: The name of the file at the specified index, or None if index is out of range. | ### path [¶](#marimo.ui.file_browser.path "Permanent link") `[](#__codelineno-0-1)path(index: int = 0) -> Path | None` Get file path at index. | PARAMETER | DESCRIPTION | | --- | --- | | `index` | Index of the file to get the path from. Defaults to 0. **TYPE:** `int` **DEFAULT:** `0` | | RETURNS | DESCRIPTION | | --- | --- | | `Path | None` | Optional\[str\]: The path of the file at the specified index, or None if index is out of range. | ### right [¶](#marimo.ui.file_browser.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.file_browser.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Form - marimo https://docs.marimo.io/api/inputs/form/ marimo.ui.form [¶](#marimo.ui.form "Permanent link") ---------------------------------------------------- `[](#__codelineno-0-1)form( [](#__codelineno-0-2) element: UIElement[S, T], [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) label: str = "", [](#__codelineno-0-16) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-17))` Bases: `UIElement[S | None, T | None]` A submittable form linked to a UIElement. Use a `form` to prevent sending UI element values to Python until a button is clicked. The value of a `form` is the value of the underlying element the last time the form was submitted. Examples: Create a form with chaining: `[](#__codelineno-0-1)# Create a form with chaining [](#__codelineno-0-2)form = mo.ui.slider(1, 100).form()` Create a form with multiple elements: `[](#__codelineno-1-1)# Create a form with multiple elements [](#__codelineno-1-2)form = ( [](#__codelineno-1-3) mo.md(''' [](#__codelineno-1-4) **Your form.** [](#__codelineno-1-5) [](#__codelineno-1-6) {name} [](#__codelineno-1-7) [](#__codelineno-1-8) {date} [](#__codelineno-1-9)''') [](#__codelineno-1-10) .batch( [](#__codelineno-1-11) name=mo.ui.text(label="name"), [](#__codelineno-1-12) date=mo.ui.date(label="date"), [](#__codelineno-1-13) ) [](#__codelineno-1-14) .form(show_clear_button=True, bordered=False) [](#__codelineno-1-15))` Instantiate a form directly: `[](#__codelineno-2-1)# Instantiate a form directly [](#__codelineno-2-2)form = mo.ui.form(element=mo.ui.slider(1, 100))` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.form.value " value property writable (marimo.ui.form.value)")` | The value of the wrapped element when the form's submit button was last clicked. **TYPE:** `Any` | | `[element](#marimo.ui.form.element " element instance-attribute (marimo.ui.form.element)")` | A copy of the wrapped element. **TYPE:** `UIElement` | | PARAMETER | DESCRIPTION | | --- | --- | | `element` | The element to wrap. **TYPE:** `UIElement[S, T]` | | `bordered` | Whether the form should have a border. Defaults to True. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. Defaults to "Submit". **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. Defaults to None. **TYPE:** `str` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. Defaults to "Clear". **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. Defaults to None. **TYPE:** `str` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if the value is invalid, or None if the value is valid. Defaults to None. **TYPE:** `Callable[[Optional[JSONType]], str | None]` **DEFAULT:** `None` | | `label` | Markdown label for the form. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None]` **DEFAULT:** `None` | ### element `instance-attribute` [¶](#marimo.ui.form.element "Permanent link") ### text `property` [¶](#marimo.ui.form.text "Permanent link") A string of HTML representing this element. ### validate `instance-attribute` [¶](#marimo.ui.form.validate "Permanent link") ### value `property` `writable` [¶](#marimo.ui.form.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.form.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.form.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.form.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.form.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.form.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### left [¶](#marimo.ui.form.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.form.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.form.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Matrix - marimo https://docs.marimo.io/api/inputs/matrix/ `[](#__codelineno-0-1)matrix( [](#__codelineno-0-2) value: list[list[Numeric]] | list[Numeric] | ArrayLike, [](#__codelineno-0-3) *, [](#__codelineno-0-4) min_value: Numeric [](#__codelineno-0-5) | list[list[Numeric]] [](#__codelineno-0-6) | list[Numeric] [](#__codelineno-0-7) | ArrayLike [](#__codelineno-0-8) | None = None, [](#__codelineno-0-9) max_value: Numeric [](#__codelineno-0-10) | list[list[Numeric]] [](#__codelineno-0-11) | list[Numeric] [](#__codelineno-0-12) | ArrayLike [](#__codelineno-0-13) | None = None, [](#__codelineno-0-14) step: Numeric [](#__codelineno-0-15) | list[list[Numeric]] [](#__codelineno-0-16) | list[Numeric] [](#__codelineno-0-17) | ArrayLike = 1.0, [](#__codelineno-0-18) disabled: bool [](#__codelineno-0-19) | list[list[bool]] [](#__codelineno-0-20) | list[bool] [](#__codelineno-0-21) | ArrayLike = False, [](#__codelineno-0-22) symmetric: bool = False, [](#__codelineno-0-23) scientific: bool = False, [](#__codelineno-0-24) precision: int | None = None, [](#__codelineno-0-25) row_labels: list[str] | None = None, [](#__codelineno-0-26) column_labels: list[str] | None = None, [](#__codelineno-0-27) debounce: bool = False, [](#__codelineno-0-28) label: str = "", [](#__codelineno-0-29))` Bases: `UIElement[list[list[Numeric]], list[list[Numeric]] | list[Numeric]]` An interactive matrix/vector editor. A matrix UI element in which each entry is a slider: click and drag horizontally on an entry to increment or decrement its value. The matrix can be configured in many ways, including element-wise bounds, element-wise steps, an element-wise disable mask, and symmetry enforcement. These configuration values may be any array-like object, including as lists, NumPy arrays, or torch Tensors. Supports both 2D (matrix) and 1D (vector) inputs. When a flat list is passed, the element displays as a column vector and `.value` returns a flat list. Examples: Basic 2D matrix: `[](#__codelineno-0-1)mat = mo.ui.matrix([[1, 0], [0, 1]]) [](#__codelineno-0-2)mat` Access the value in another cell with `[](#__codelineno-1-1)mat.value # [[1, 0], [0, 1]]` Column vector (1D input): `[](#__codelineno-2-1)v = mo.ui.matrix([1, 2, 3]) [](#__codelineno-2-2)v.value # [1, 2, 3]` Row vecto `[](#__codelineno-3-1)v = mo.ui.matrix([[1, 2, 3]]) [](#__codelineno-3-2)v.value # [[1, 2, 3]]` You can specify bounds and a step size as well: `[](#__codelineno-4-1)mat = mo.ui.matrix( [](#__codelineno-4-2) [[1, 0], [0, 1]], [](#__codelineno-4-3) min_value=-10, [](#__codelineno-4-4) max_value=10, [](#__codelineno-4-5) step=0.5, [](#__codelineno-4-6))` To disable editing of some or all entries, use the disabled argument: `[](#__codelineno-5-1)mat = mo.ui.matrix( [](#__codelineno-5-2) [[1, 0], [0, 1]], [](#__codelineno-5-3) # Disable editing the diagonal values [](#__codelineno-5-4) disabled=[[True, False], [False, True]], [](#__codelineno-5-5))` The value, bounds, step, and disabled arguments can optionally be NumPy arrays, interpreted elementwise. `[](#__codelineno-6-1)import numpy as np [](#__codelineno-6-2)[](#__codelineno-6-3)mat = mo.ui.matrix(np.eye(2)) [](#__codelineno-6-4)mat` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.matrix.value " value property writable (marimo.ui.matrix.value)")` | The current matrix as a nested list, or a flat list when created with 1D input. Use `np.asarray(matrix.value)` to convert to a numpy array. **TYPE:** `list[list[Numeric]] | list[Numeric]` | | PARAMETER | DESCRIPTION | | --- | --- | | `value` | Initial data. A nested list or 2D array creates a matrix; a flat list or 1D array creates a column vector. Rows and columns are inferred from the shape. **TYPE:** `list[list[Numeric]] | list[Numeric] | ArrayLike` | | `min_value` | Minimum allowed value. A scalar is broadcast to all cells; a list or numpy array sets per-element bounds. For 1D input, accepts a flat list. None means unbounded. Defaults to None. **TYPE:** `Numeric | list[list[Numeric]] | list[Numeric] | ArrayLike | None` **DEFAULT:** `None` | | `max_value` | Maximum allowed value. A scalar is broadcast to all cells; a list or numpy array sets per-element bounds. For 1D input, accepts a flat list. None means unbounded. Defaults to None. **TYPE:** `Numeric | list[list[Numeric]] | list[Numeric] | ArrayLike | None` **DEFAULT:** `None` | | `step` | Drag increment. A scalar is broadcast to all cells; a list or numpy array sets per-element step sizes. For 1D input, accepts a flat list. Defaults to 1.0. **TYPE:** `Numeric | list[list[Numeric]] | list[Numeric] | ArrayLike` **DEFAULT:** `1.0` | | `disabled` | Whether cells are disabled. A scalar bool is broadcast to all cells; a list or numpy bool array sets a per-element mask. For 1D input, accepts a flat list. Defaults to False. **TYPE:** `bool | list[list[bool]] | list[bool] | ArrayLike` **DEFAULT:** `False` | | `symmetric` | If True, editing cell `[i][j]` also updates cell `[j][i]`. Requires a square matrix. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `scientific` | If True, display values in scientific notation (e.g., `1.0e-4`). Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `precision` | Number of decimal places displayed. When None, inferred from the data values and step sizes. Defaults to None. **TYPE:** `int | None` **DEFAULT:** `None` | | `row_labels` | Labels for each row. Defaults to None. **TYPE:** `list[str] | None` **DEFAULT:** `None` | | `column_labels` | Labels for each column. Defaults to None. **TYPE:** `list[str] | None` **DEFAULT:** `None` | | `debounce` | If True, value updates are only sent to the backend on mouse-up (pointer release) instead of on every drag movement. Useful when the matrix drives expensive downstream computations. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `label` | Markdown/LaTeX label for the element. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | ### text `property` [¶](#marimo.ui.matrix.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.matrix.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.matrix.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.matrix.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.matrix.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.matrix.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.matrix.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### left [¶](#marimo.ui.matrix.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.matrix.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.matrix.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Microphone - marimo https://docs.marimo.io/api/inputs/microphone/ marimo.ui.microphone [¶](#marimo.ui.microphone "Permanent link") ---------------------------------------------------------------- `[](#__codelineno-0-1)microphone( [](#__codelineno-0-2) *, [](#__codelineno-0-3) label: str = "", [](#__codelineno-0-4) on_change: Callable[[BytesIO], None] | None = None, [](#__codelineno-0-5))` Bases: `UIElement[str, BytesIO]` An audio recorder element. Use `mo.ui.microphone` to record audio via the user's browser. The user must grant permission to use the microphone. Examples: `[](#__codelineno-0-1)mic = mo.ui.microphone() [](#__codelineno-0-2)mic` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.microphone.value " value property writable (marimo.ui.microphone.value)")` | The blob of the recorded audio, as an `io.BytesIO` object. **TYPE:** `BytesIO` | | PARAMETER | DESCRIPTION | | --- | --- | | `label` | Markdown label for the element. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | `on_change` | Optional callback to run when this element's value changes. **TYPE:** `Callable[[BytesIO], None] | None` **DEFAULT:** `None` | ### name `class-attribute` `instance-attribute` [¶](#marimo.ui.microphone.name "Permanent link") `[](#__codelineno-0-1)name: Final[str] = 'marimo-microphone'` ### text `property` [¶](#marimo.ui.microphone.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.microphone.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.microphone.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.microphone.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.microphone.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.microphone.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.microphone.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### left [¶](#marimo.ui.microphone.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.microphone.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.microphone.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Multiselect - marimo https://docs.marimo.io/api/inputs/multiselect/ marimo.ui.multiselect [¶](#marimo.ui.multiselect "Permanent link") ------------------------------------------------------------------ `[](#__codelineno-0-1)multiselect( [](#__codelineno-0-2) options: Sequence[Any] | dict[str, Any], [](#__codelineno-0-3) value: Sequence[Any] | None = None, [](#__codelineno-0-4) *, [](#__codelineno-0-5) label: str = "", [](#__codelineno-0-6) on_change: Callable[[list[object]], None] | None = None, [](#__codelineno-0-7) full_width: bool = False, [](#__codelineno-0-8) max_selections: int | None = None, [](#__codelineno-0-9))` Bases: `UIElement[list[str], list[object]]` A multiselect input. Examples: `[](#__codelineno-0-1)multiselect = mo.ui.multiselect( [](#__codelineno-0-2) options=["a", "b", "c"], label="choose some options" [](#__codelineno-0-3))` Or from a dataframe series: `[](#__codelineno-1-1)multiselect = mo.ui.multiselect.from_series(df["column_name"])` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.multiselect.value " value property writable (marimo.ui.multiselect.value)")` | The selected values, or None if no selection. **TYPE:** `List[object]` | | `[options](#marimo.ui.multiselect.options " options instance-attribute (marimo.ui.multiselect.options)")` | A dict mapping option name to option value. **TYPE:** `dict` | | PARAMETER | DESCRIPTION | | --- | --- | | `options` | Sequence of options, or dict mapping option name to option value. If the options are not strings, they will be converted to strings when displayed in the dropdown. **TYPE:** `Sequence[Any] | dict[str, Any]` | | `value` | A list of initially selected options. Defaults to None. **TYPE:** `Sequence[str]` **DEFAULT:** `None` | | `label` | Markdown label for the element. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[List[object]], None]` **DEFAULT:** `None` | | `full_width` | Whether the input should take up the full width of its container. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `max_selections` | Maximum number of items that can be selected. Defaults to None. **TYPE:** `int` **DEFAULT:** `None` | ### options `instance-attribute` [¶](#marimo.ui.multiselect.options "Permanent link") ### text `property` [¶](#marimo.ui.multiselect.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.multiselect.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.multiselect.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.multiselect.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.multiselect.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.multiselect.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.multiselect.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### from\_series `staticmethod` [¶](#marimo.ui.multiselect.from_series "Permanent link") `[](#__codelineno-0-1)from_series( [](#__codelineno-0-2) series: DataFrameSeries, **kwargs: Any [](#__codelineno-0-3)) -> [multiselect](#marimo.ui.multiselect " marimo.ui.multiselect (marimo._plugins.ui._impl.input.multiselect)")` Create a multiselect from a dataframe series. ### left [¶](#marimo.ui.multiselect.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.multiselect.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.multiselect.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Navigation Menu - marimo https://docs.marimo.io/api/inputs/nav_menu/ `[](#__codelineno-0-1)nav_menu( [](#__codelineno-0-2) menu: dict[str, JSONType], [](#__codelineno-0-3) *, [](#__codelineno-0-4) orientation: Literal[ [](#__codelineno-0-5) "horizontal", "vertical" [](#__codelineno-0-6) ] = "horizontal", [](#__codelineno-0-7)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Navigation menu component. This is useful for creating a navigation menu with hyperlinks, most used when creating multi-page applications, with `marimo.create_asgi_app` ([docs](https://docs.marimo.io/guides/deploying/programmatically.html)). | PARAMETER | DESCRIPTION | | --- | --- | | `menu` | a dictionary of tab names to tab content; the content can also be nested dictionaries (one level deep) strings are interpreted as markdown **TYPE:** `dict[str, JSONType]` | | `orientation` | The orientation of the menu. **TYPE:** `Literal['horizontal', 'vertical']` **DEFAULT:** `'horizontal'` | | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | Example `[](#__codelineno-0-1)nav_menu = mo.nav_menu( [](#__codelineno-0-2) { [](#__codelineno-0-3) "/overview": "Overview", [](#__codelineno-0-4) "/sales": f"{mo.icon('lucide:shopping-cart')} Sales", [](#__codelineno-0-5) "/products": f"{mo.icon('lucide:package')} Products", [](#__codelineno-0-6) } [](#__codelineno-0-7))` `[](#__codelineno-1-1)nav_menu = mo.nav_menu( [](#__codelineno-1-2) { [](#__codelineno-1-3) "/overview": "Overview", [](#__codelineno-1-4) "Sales": { [](#__codelineno-1-5) "/sales": "Overview", [](#__codelineno-1-6) "/sales/invoices": { [](#__codelineno-1-7) "label": "Invoices", [](#__codelineno-1-8) "description": "View invoices", [](#__codelineno-1-9) }, [](#__codelineno-1-10) "/sales/customers": { [](#__codelineno-1-11) "label": "Customers", [](#__codelineno-1-12) "description": "View customers", [](#__codelineno-1-13) }, [](#__codelineno-1-14) }, [](#__codelineno-1-15) } [](#__codelineno-1-16))` Number - marimo https://docs.marimo.io/api/inputs/number/ marimo.ui.number [¶](#marimo.ui.number "Permanent link") -------------------------------------------------------- `[](#__codelineno-0-1)number( [](#__codelineno-0-2) start: float | None = None, [](#__codelineno-0-3) stop: float | None = None, [](#__codelineno-0-4) step: float | None = None, [](#__codelineno-0-5) value: float | None = None, [](#__codelineno-0-6) debounce: bool = False, [](#__codelineno-0-7) *, [](#__codelineno-0-8) label: str = "", [](#__codelineno-0-9) on_change: Callable[[Optional[Numeric]], None] [](#__codelineno-0-10) | None = None, [](#__codelineno-0-11) full_width: bool = False, [](#__codelineno-0-12) disabled: bool = False, [](#__codelineno-0-13))` Bases: `UIElement[Numeric | None, Numeric | None]` A number picker over an interval. Example `[](#__codelineno-0-1)number = mo.ui.number(start=1, stop=10, step=2)` Or for integer-only values: `[](#__codelineno-1-1)number = mo.ui.number(step=1)` Or from a dataframe series: `[](#__codelineno-2-1)number = mo.ui.number.from_series(df["column_name"])` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.number.value " value property writable (marimo.ui.number.value)")` | The value of the number, possibly `None`. **TYPE:** `Numeric | None` | | `[start](#marimo.ui.number.start " start instance-attribute (marimo.ui.number.start)")` | The minimum value of the interval. **TYPE:** `float | None` | | `[stop](#marimo.ui.number.stop " stop instance-attribute (marimo.ui.number.stop)")` | The maximum value of the interval. **TYPE:** `float | None` | | `[step](#marimo.ui.number.step " step instance-attribute (marimo.ui.number.step)")` | The number increment. **TYPE:** `float | None` | | PARAMETER | DESCRIPTION | | --- | --- | | `start` | The minimum value of the interval. Defaults to None. **TYPE:** `float | None` **DEFAULT:** `None` | | `stop` | The maximum value of the interval. Defaults to None. **TYPE:** `float | None` **DEFAULT:** `None` | | `step` | The number increment. Defaults to None. **TYPE:** `float | None` **DEFAULT:** `None` | | `value` | The default value. Defaults to None. **TYPE:** `float | None` **DEFAULT:** `None` | | `debounce` | Whether to debounce (rate-limit) value updates from the frontend. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `label` | Markdown label for the element. Defaults to an empty string. **TYPE:** `str` **DEFAULT:** `''` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[Numeric]], None] | None` **DEFAULT:** `None` | | `full_width` | Whether the input should take up the full width of its container. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `disabled` | Whether the input is disabled. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | METHOD | DESCRIPTION | | --- | --- | | `[from_series](#marimo.ui.number.from_series " from_series staticmethod (marimo.ui.number.from_series)")` | DataFrameSeries, \*\*kwargs: Any) -> number: Create a number picker from a dataframe series. | ### start `instance-attribute` [¶](#marimo.ui.number.start "Permanent link") ### step `instance-attribute` [¶](#marimo.ui.number.step "Permanent link") ### stop `instance-attribute` [¶](#marimo.ui.number.stop "Permanent link") ### text `property` [¶](#marimo.ui.number.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.number.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.number.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.number.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.number.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.number.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.number.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### from\_series `staticmethod` [¶](#marimo.ui.number.from_series "Permanent link") `[](#__codelineno-0-1)from_series( [](#__codelineno-0-2) series: DataFrameSeries, **kwargs: Any [](#__codelineno-0-3)) -> [number](#marimo.ui.number " marimo.ui.number (marimo._plugins.ui._impl.input.number)")` Create a number picker from a dataframe series. ### left [¶](#marimo.ui.number.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.number.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.number.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Radio - marimo https://docs.marimo.io/api/inputs/radio/ marimo.ui.radio [¶](#marimo.ui.radio "Permanent link") ------------------------------------------------------ `[](#__codelineno-0-1)radio( [](#__codelineno-0-2) options: Sequence[str] | dict[str, Any], [](#__codelineno-0-3) value: str | None = None, [](#__codelineno-0-4) inline: bool = False, [](#__codelineno-0-5) *, [](#__codelineno-0-6) label: str = "", [](#__codelineno-0-7) on_change: Callable[[Any], None] | None = None, [](#__codelineno-0-8) disabled: bool = False, [](#__codelineno-0-9))` Bases: `UIElement[str | None, Any]` A radio group. Examples: `[](#__codelineno-0-1)radiogroup = mo.ui.radio( [](#__codelineno-0-2) options=["a", "b", "c"], value="a", label="choose one" [](#__codelineno-0-3))` `[](#__codelineno-1-1)radiogroup = mo.ui.radio( [](#__codelineno-1-2) options={"one": 1, "two": 2, "three": 3}, [](#__codelineno-1-3) value="one", [](#__codelineno-1-4) label="pick a number", [](#__codelineno-1-5))` Or from a dataframe series: `[](#__codelineno-2-1)radiogroup = mo.ui.radio.from_series(df["column_name"])` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.radio.value " value property writable (marimo.ui.radio.value)")` | The value of the selected radio option. **TYPE:** `Any` | | `[options](#marimo.ui.radio.options " options instance-attribute (marimo.ui.radio.options)")` | A dict mapping option name to option value. **TYPE:** `dict` | | PARAMETER | DESCRIPTION | | --- | --- | | `options` | Sequence of text options, or dict mapping option name to option value. **TYPE:** `Sequence[str] | dict[str, Any]` | | `value` | Default option name, if None, starts with nothing checked. Defaults to None. **TYPE:** `str` **DEFAULT:** `None` | | `inline` | Whether to display options inline. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `label` | Optional markdown label for the element. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Any], None]` **DEFAULT:** `None` | | `disabled` | Whether the radio group is disabled. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | ### options `instance-attribute` [¶](#marimo.ui.radio.options "Permanent link") ### text `property` [¶](#marimo.ui.radio.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.radio.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.radio.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.radio.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.radio.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.radio.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.radio.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### from\_series `staticmethod` [¶](#marimo.ui.radio.from_series "Permanent link") `[](#__codelineno-0-1)from_series( [](#__codelineno-0-2) series: DataFrameSeries, **kwargs: Any [](#__codelineno-0-3)) -> [radio](#marimo.ui.radio " marimo.ui.radio (marimo._plugins.ui._impl.input.radio)")` Create a radio group from a dataframe series. ### left [¶](#marimo.ui.radio.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.radio.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.radio.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Range Slider - marimo https://docs.marimo.io/api/inputs/range_slider/ marimo.ui.range\_slider [¶](#marimo.ui.range_slider "Permanent link") --------------------------------------------------------------------- `[](#__codelineno-0-1)range_slider( [](#__codelineno-0-2) start: Numeric | None = None, [](#__codelineno-0-3) stop: Numeric | None = None, [](#__codelineno-0-4) step: Numeric | None = None, [](#__codelineno-0-5) value: Sequence[Numeric] | None = None, [](#__codelineno-0-6) debounce: bool = False, [](#__codelineno-0-7) orientation: Literal[ [](#__codelineno-0-8) "horizontal", "vertical" [](#__codelineno-0-9) ] = "horizontal", [](#__codelineno-0-10) show_value: bool = False, [](#__codelineno-0-11) steps: Sequence[Numeric] | None = None, [](#__codelineno-0-12) *, [](#__codelineno-0-13) label: str = "", [](#__codelineno-0-14) on_change: Callable[[Sequence[Numeric]], None] [](#__codelineno-0-15) | None = None, [](#__codelineno-0-16) full_width: bool = False, [](#__codelineno-0-17) disabled: bool = False, [](#__codelineno-0-18))` Bases: `UIElement[list[Numeric], Sequence[Numeric]]` A numeric slider for specifying a range over an interval. Example `[](#__codelineno-0-1)range_slider = mo.ui.range_slider( [](#__codelineno-0-2) start=1, stop=10, step=2, value=[2, 6] [](#__codelineno-0-3))` Or from a dataframe series: `[](#__codelineno-1-1)range_slider = mo.ui.range_slider.from_series(df["column_name"])` Or using numpy arrays: `[](#__codelineno-2-1)import numpy as np [](#__codelineno-2-2)[](#__codelineno-2-3)steps = np.array([1, 2, 3, 4, 5]) [](#__codelineno-2-4)# linear steps [](#__codelineno-2-5)range_slider = mo.ui.range_slider(steps=steps) [](#__codelineno-2-6)# log steps [](#__codelineno-2-7)log_range_slider = mo.ui.range_slider(steps=np.logspace(0, 3, 4)) [](#__codelineno-2-8)# power steps [](#__codelineno-2-9)power_range_slider = mo.ui.range_slider(steps=np.power([1, 2, 3], 2))` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.range_slider.value " value property writable (marimo.ui.range_slider.value)")` | The current range value of the slider. **TYPE:** `list[Numeric]` | | `[start](#marimo.ui.range_slider.start " start instance-attribute (marimo.ui.range_slider.start)")` | The minimum value of the interval. **TYPE:** `Numeric` | | `[stop](#marimo.ui.range_slider.stop " stop instance-attribute (marimo.ui.range_slider.stop)")` | The maximum value of the interval. **TYPE:** `Numeric` | | `[step](#marimo.ui.range_slider.step " step instance-attribute (marimo.ui.range_slider.step)")` | The slider increment. **TYPE:** `Numeric | None` | | `[steps](#marimo.ui.range_slider.steps " steps instance-attribute (marimo.ui.range_slider.steps)")` | List of steps. **TYPE:** `Sequence[Numeric] | None` | | PARAMETER | DESCRIPTION | | --- | --- | | `start` | The minimum value of the interval. **TYPE:** `Numeric | None` **DEFAULT:** `None` | | `stop` | The maximum value of the interval. **TYPE:** `Numeric | None` **DEFAULT:** `None` | | `step` | The slider increment. **TYPE:** `Numeric | None` **DEFAULT:** `None` | | `value` | Default value. **TYPE:** `Sequence[Numeric] | None` **DEFAULT:** `None` | | `debounce` | Whether to debounce the slider to only send the value on mouse-up or drag-end. **TYPE:** `bool` **DEFAULT:** `False` | | `orientation` | The orientation of the slider, either "horizontal" or "vertical". **TYPE:** `Literal['horizontal', 'vertical']` **DEFAULT:** `'horizontal'` | | `show_value` | Whether to display the current value of the slider. **TYPE:** `bool` **DEFAULT:** `False` | | `steps` | List of steps to customize the slider, mutually exclusive with `start`, `stop`, and `step`. **TYPE:** `Sequence[Numeric] | None` **DEFAULT:** `None` | | `label` | Markdown label for the element. **TYPE:** `str` **DEFAULT:** `''` | | `on_change` | Optional callback to run when this element's value changes. **TYPE:** `Callable[[Sequence[Numeric]], None] | None` **DEFAULT:** `None` | | `full_width` | Whether the input should take up the full width of its container. **TYPE:** `bool` **DEFAULT:** `False` | | `disabled` | Whether the slider is disabled. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | METHOD | DESCRIPTION | | --- | --- | | `[from_series](#marimo.ui.range_slider.from_series " from_series staticmethod (marimo.ui.range_slider.from_series)")` | DataFrameSeries, \*\*kwargs: Any) -> range\_slider: Create a range slider from a dataframe series. | ### start `instance-attribute` [¶](#marimo.ui.range_slider.start "Permanent link") ### step `instance-attribute` [¶](#marimo.ui.range_slider.step "Permanent link") ### steps `instance-attribute` [¶](#marimo.ui.range_slider.steps "Permanent link") `[](#__codelineno-0-1)steps: Sequence[Numeric] | None` ### stop `instance-attribute` [¶](#marimo.ui.range_slider.stop "Permanent link") ### text `property` [¶](#marimo.ui.range_slider.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.range_slider.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.range_slider.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.range_slider.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.range_slider.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.range_slider.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.range_slider.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### from\_series `staticmethod` [¶](#marimo.ui.range_slider.from_series "Permanent link") `[](#__codelineno-0-1)from_series( [](#__codelineno-0-2) series: DataFrameSeries, **kwargs: Any [](#__codelineno-0-3)) -> [range_slider](#marimo.ui.range_slider " marimo.ui.range_slider (marimo._plugins.ui._impl.input.range_slider)")` Create a range slider from a dataframe series. ### left [¶](#marimo.ui.range_slider.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.range_slider.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.range_slider.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Refresh - marimo https://docs.marimo.io/api/inputs/refresh/ marimo.ui.refresh [¶](#marimo.ui.refresh "Permanent link") ---------------------------------------------------------- `[](#__codelineno-0-1)refresh( [](#__codelineno-0-2) options: list[int | float | str] | None = None, [](#__codelineno-0-3) default_interval: int | float | str | None = None, [](#__codelineno-0-4) *, [](#__codelineno-0-5) label: str = "", [](#__codelineno-0-6) on_change: Callable[[int], None] | None = None, [](#__codelineno-0-7))` Bases: `UIElement[int, int]` A refresh button that will auto-refresh its descendants for a given interval. Each option value can either be a number (int or float) in seconds or a human-readable string (e.g. "1s", "10s", "1m"). You can also combine multiple time units (e.g. "1m 30s"). Note The refresh interval may not be exact, as it depends on the time it takes to render the content and the time it takes to send the content to the client. Also, due to the buffering of UI element changes, if the downstream cells take a long time to render, the refresh interval may be longer than expected. Examples: `[](#__codelineno-0-1)refresh_button = mo.ui.refresh( [](#__codelineno-0-2) options=["1m", "5m 30s", "10m"], [](#__codelineno-0-3) default_interval="10m", [](#__codelineno-0-4)) [](#__codelineno-0-5)refresh_button` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.refresh.value " value property writable (marimo.ui.refresh.value)")` | The time in seconds since the refresh has been activated. **TYPE:** `int` | | PARAMETER | DESCRIPTION | | --- | --- | | `options` | The options for the refresh interval, as a list of human-readable strings or numbers (int or float) in seconds. If no options are provided and default\_interval is provided, the options will be generated automatically. If no options are provided and default\_interval is not provided, the refresh button will not be displayed with a dropdown for auto-refresh. **TYPE:** `list[int | float | str] | None` **DEFAULT:** `None` | | `default_interval` | The default value of the refresh interval. **TYPE:** `int | float | str | None` **DEFAULT:** `None` | | `label` | Markdown label for the element. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | `on_change` | Optional callback to run when this element's value changes. **TYPE:** `Callable[[int], None] | None` **DEFAULT:** `None` | ### name `class-attribute` `instance-attribute` [¶](#marimo.ui.refresh.name "Permanent link") `[](#__codelineno-0-1)name: Final[str] = 'marimo-refresh'` ### text `property` [¶](#marimo.ui.refresh.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.refresh.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.refresh.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.refresh.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.refresh.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.refresh.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.refresh.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### left [¶](#marimo.ui.refresh.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.refresh.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.refresh.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Run Button - marimo https://docs.marimo.io/api/inputs/run_button/ Source code for `examples/ui/run_button.py` Tip: paste this code into an empty cell, and the marimo editor will create cells for you `import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(mo): first_button = mo.ui.run_button(label="Option 1") second_button = mo.ui.run_button(label="Option 2") first_button, second_button return first_button, second_button @app.cell def _(first_button, second_button): if first_button.value: print("You chose option 1!") elif second_button.value: print("You chose option 2!") else: print("Click a button!") return if __name__ == "__main__": app.run()` marimo.ui.run\_button [¶](#marimo.ui.run_button "Permanent link") ----------------------------------------------------------------- `[](#__codelineno-0-1)run_button( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "success", "warn", "danger" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5) disabled: bool = False, [](#__codelineno-0-6) tooltip: str | None = None, [](#__codelineno-0-7) *, [](#__codelineno-0-8) label: str = "click to run", [](#__codelineno-0-9) on_change: Callable[[Any], None] | None = None, [](#__codelineno-0-10) full_width: bool = False, [](#__codelineno-0-11) keyboard_shortcut: str | None = None, [](#__codelineno-0-12))` Bases: `UIElement[Any, Any]` A button that can be used to trigger computation. When clicked, run\_button's value is set to True, and any cells referencing it are run. After those cells are run, run\_button's value will automatically be set back to False as long as automatic execution is enabled. Examples: `[](#__codelineno-0-1)# a button that when clicked will have its value set to True; [](#__codelineno-0-2)# any cells referencing that button will automatically run. [](#__codelineno-0-3)button = mo.ui.run_button() [](#__codelineno-0-4)button` `[](#__codelineno-1-1)slider = mo.ui.slider(1, 10) [](#__codelineno-1-2)slider` `[](#__codelineno-2-1)# if the button hasn't been clicked, don't run. [](#__codelineno-2-2)mo.stop(not button.value) [](#__codelineno-2-3)[](#__codelineno-2-4)slider.value` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.run_button.value " value property writable (marimo.ui.run_button.value)")` | The value of the button; True when clicked, and reset to False after cells referencing the button finish running (when automatic execution is enabled). **TYPE:** `bool` | | PARAMETER | DESCRIPTION | | --- | --- | | `kind` | Button style. Defaults to "neutral". **TYPE:** `Literal['neutral', 'success', 'warn', 'danger']` **DEFAULT:** `'neutral'` | | `disabled` | Whether the button is disabled. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `tooltip` | A tooltip to display for the button. Defaults to None. **TYPE:** `str` **DEFAULT:** `None` | | `label` | Markdown label for the element. Defaults to "click to run". **TYPE:** `str` **DEFAULT:** `'click to run'` | | `on_change` | Optional callback to run when this element's value changes. **TYPE:** `Callable[[Any], None]` **DEFAULT:** `None` | | `full_width` | Whether the input should take up the full width of its container. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `keyboard_shortcut` | Keyboard shortcut to trigger the button (e.g. 'Ctrl-L'). Defaults to None. **TYPE:** `str` **DEFAULT:** `None` | ### text `property` [¶](#marimo.ui.run_button.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.run_button.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.run_button.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.run_button.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.run_button.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.run_button.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.run_button.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### left [¶](#marimo.ui.run_button.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.run_button.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.run_button.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Slider - marimo https://docs.marimo.io/api/inputs/slider/ marimo.ui.slider [¶](#marimo.ui.slider "Permanent link") -------------------------------------------------------- `[](#__codelineno-0-1)slider( [](#__codelineno-0-2) start: Numeric | None = None, [](#__codelineno-0-3) stop: Numeric | None = None, [](#__codelineno-0-4) step: Numeric | None = None, [](#__codelineno-0-5) value: Numeric | None = None, [](#__codelineno-0-6) debounce: bool = False, [](#__codelineno-0-7) disabled: bool = False, [](#__codelineno-0-8) orientation: Literal[ [](#__codelineno-0-9) "horizontal", "vertical" [](#__codelineno-0-10) ] = "horizontal", [](#__codelineno-0-11) show_value: bool = False, [](#__codelineno-0-12) include_input: bool = False, [](#__codelineno-0-13) steps: Sequence[Numeric] | None = None, [](#__codelineno-0-14) *, [](#__codelineno-0-15) label: str = "", [](#__codelineno-0-16) on_change: Callable[[Optional[Numeric]], None] [](#__codelineno-0-17) | None = None, [](#__codelineno-0-18) full_width: bool = False, [](#__codelineno-0-19))` Bases: `UIElement[Numeric, Numeric]` A numeric slider over an interval. Example `[](#__codelineno-0-1)slider = mo.ui.slider(start=1, stop=10, step=2)` Or from a dataframe series: `[](#__codelineno-1-1)slider = mo.ui.slider.from_series(df["column_name"])` Or using numpy arrays: `[](#__codelineno-2-1)import numpy as np [](#__codelineno-2-2)[](#__codelineno-2-3)# linear steps [](#__codelineno-2-4)steps = np.array([1, 2, 3, 4, 5]) [](#__codelineno-2-5)slider = mo.ui.slider(steps=steps) [](#__codelineno-2-6)# log steps [](#__codelineno-2-7)log_slider = mo.ui.slider(steps=np.logspace(0, 3, 4)) [](#__codelineno-2-8)# power steps [](#__codelineno-2-9)power_slider = mo.ui.slider(steps=np.power([1, 2, 3], 2))` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.slider.value " value property writable (marimo.ui.slider.value)")` | The current numeric value of the slider. **TYPE:** `Numeric` | | `[start](#marimo.ui.slider.start " start instance-attribute (marimo.ui.slider.start)")` | The minimum value of the interval. **TYPE:** `Numeric` | | `[stop](#marimo.ui.slider.stop " stop instance-attribute (marimo.ui.slider.stop)")` | The maximum value of the interval. **TYPE:** `Numeric` | | `[step](#marimo.ui.slider.step " step instance-attribute (marimo.ui.slider.step)")` | The slider increment. **TYPE:** `Numeric | None` | | `[steps](#marimo.ui.slider.steps " steps instance-attribute (marimo.ui.slider.steps)")` | List of steps. **TYPE:** `Sequence[Numeric] | None` | | PARAMETER | DESCRIPTION | | --- | --- | | `start` | The minimum value of the interval. **TYPE:** `Numeric | None` **DEFAULT:** `None` | | `stop` | The maximum value of the interval. **TYPE:** `Numeric | None` **DEFAULT:** `None` | | `step` | The slider increment. **TYPE:** `Numeric | None` **DEFAULT:** `None` | | `value` | Default value. **TYPE:** `Numeric | None` **DEFAULT:** `None` | | `debounce` | Whether to debounce the slider to only send the value on mouse-up or drag-end. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `disabled` | Whether the slider is disabled. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `orientation` | The orientation of the slider, either "horizontal" or "vertical". Defaults to "horizontal". **TYPE:** `Literal['horizontal', 'vertical']` **DEFAULT:** `'horizontal'` | | `show_value` | Whether to display the current value of the slider. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `include_input` | Whether to display an editable input with the current value of the slider. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `steps` | List of steps to customize the slider, mutually exclusive with `start`, `stop`, and `step`. **TYPE:** `Sequence[Numeric] | None` **DEFAULT:** `None` | | `label` | Markdown label for the element. Defaults to an empty string. **TYPE:** `str` **DEFAULT:** `''` | | `on_change` | Optional callback to run when this element's value changes. **TYPE:** `Callable[[Optional[Numeric]], None] | None` **DEFAULT:** `None` | | `full_width` | Whether the input should take up the full width of its container. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | RAISES | DESCRIPTION | | --- | --- | | `ValueError` | If `steps` is provided along with `start`, `stop`, or `step`. | | `ValueError` | If neither `steps` nor both `start` and `stop` are provided. | | `ValueError` | If `stop` is less than `start`. | | `ValueError` | If `value` is out of bounds. | | `TypeError` | If `steps` is not a sequence of numbers. | | METHOD | DESCRIPTION | | --- | --- | | `[from_series](#marimo.ui.slider.from_series " from_series staticmethod (marimo.ui.slider.from_series)")` | DataFrameSeries, \*\*kwargs: Any) -> slider: Create a slider from a dataframe series. | ### start `instance-attribute` [¶](#marimo.ui.slider.start "Permanent link") ### step `instance-attribute` [¶](#marimo.ui.slider.step "Permanent link") ### steps `instance-attribute` [¶](#marimo.ui.slider.steps "Permanent link") `[](#__codelineno-0-1)steps: Sequence[Numeric] | None` ### stop `instance-attribute` [¶](#marimo.ui.slider.stop "Permanent link") ### text `property` [¶](#marimo.ui.slider.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.slider.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.slider.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.slider.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.slider.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.slider.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.slider.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### from\_series `staticmethod` [¶](#marimo.ui.slider.from_series "Permanent link") `[](#__codelineno-0-1)from_series( [](#__codelineno-0-2) series: DataFrameSeries, **kwargs: Any [](#__codelineno-0-3)) -> [slider](#marimo.ui.slider " marimo.ui.slider (marimo._plugins.ui._impl.input.slider)")` Create a slider from a dataframe series. ### left [¶](#marimo.ui.slider.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.slider.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.slider.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Switch - marimo https://docs.marimo.io/api/inputs/switch/ marimo.ui.switch [¶](#marimo.ui.switch "Permanent link") -------------------------------------------------------- `[](#__codelineno-0-1)switch( [](#__codelineno-0-2) value: bool = False, [](#__codelineno-0-3) *, [](#__codelineno-0-4) label: str = "", [](#__codelineno-0-5) disabled: bool = False, [](#__codelineno-0-6) on_change: Callable[[bool], None] | None = None, [](#__codelineno-0-7))` Bases: `UIElement[bool, bool]` A boolean switch. Examples: | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.switch.value " value property writable (marimo.ui.switch.value)")` | A boolean, `True` if checked. **TYPE:** `bool` | | PARAMETER | DESCRIPTION | | --- | --- | | `value` | Default value, True or False. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `label` | Markdown label for the element. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | `on_change` | Optional callback to run when this element's value changes. **TYPE:** `Callable[[bool], None] | None` **DEFAULT:** `None` | | `disabled` | Whether the element is disabled. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | ### text `property` [¶](#marimo.ui.switch.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.switch.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.switch.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.switch.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.switch.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.switch.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.switch.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### left [¶](#marimo.ui.switch.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.switch.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.switch.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Table - marimo https://docs.marimo.io/api/inputs/table/ `[](#__codelineno-0-1)table( [](#__codelineno-0-2) data: ListOrTuple[ [](#__codelineno-0-3) str | int | float | bool | MIME | None [](#__codelineno-0-4) ] [](#__codelineno-0-5) | ListOrTuple[dict[str, JSONType]] [](#__codelineno-0-6) | dict[str, ListOrTuple[JSONType]] [](#__codelineno-0-7) | IntoDataFrame, [](#__codelineno-0-8) pagination: bool | None = None, [](#__codelineno-0-9) selection: Literal[ [](#__codelineno-0-10) "single", "multi", "single-cell", "multi-cell" [](#__codelineno-0-11) ] [](#__codelineno-0-12) | None = "multi", [](#__codelineno-0-13) initial_selection: list[int] [](#__codelineno-0-14) | list[tuple[str, str]] [](#__codelineno-0-15) | None = None, [](#__codelineno-0-16) page_size: int | None = None, [](#__codelineno-0-17) show_column_summaries: ShowColumnSummaries [](#__codelineno-0-18) | None = None, [](#__codelineno-0-19) show_data_types: bool = True, [](#__codelineno-0-20) format_mapping: dict[str, str | Callable[..., Any]] [](#__codelineno-0-21) | None = None, [](#__codelineno-0-22) freeze_columns_left: Sequence[str] | None = None, [](#__codelineno-0-23) freeze_columns_right: Sequence[str] | None = None, [](#__codelineno-0-24) text_justify_columns: dict[ [](#__codelineno-0-25) str, Literal["left", "center", "right"] [](#__codelineno-0-26) ] [](#__codelineno-0-27) | None = None, [](#__codelineno-0-28) wrapped_columns: list[str] | None = None, [](#__codelineno-0-29) header_tooltip: dict[str, str] | None = None, [](#__codelineno-0-30) show_download: bool = True, [](#__codelineno-0-31) max_columns: MaxColumnsType = MAX_COLUMNS_NOT_PROVIDED, [](#__codelineno-0-32) *, [](#__codelineno-0-33) label: str = "", [](#__codelineno-0-34) on_change: Callable[ [](#__codelineno-0-35) [ [](#__codelineno-0-36) Union[ [](#__codelineno-0-37) list[JSONType], [](#__codelineno-0-38) dict[str, ListOrTuple[JSONType]], [](#__codelineno-0-39) IntoDataFrame, [](#__codelineno-0-40) list[TableCell], [](#__codelineno-0-41) ] [](#__codelineno-0-42) ], [](#__codelineno-0-43) None, [](#__codelineno-0-44) ] [](#__codelineno-0-45) | None = None, [](#__codelineno-0-46) style_cell: Callable[[str, str, Any], dict[str, Any]] [](#__codelineno-0-47) | None = None, [](#__codelineno-0-48) hover_template: str [](#__codelineno-0-49) | Callable[[str, str, Any], str] [](#__codelineno-0-50) | None = None, [](#__codelineno-0-51) max_height: int | None = None, [](#__codelineno-0-52) _internal_column_charts_row_limit: int | None = None, [](#__codelineno-0-53) _internal_summary_row_limit: int | None = None, [](#__codelineno-0-54) _internal_total_rows: int [](#__codelineno-0-55) | Literal["too_many"] [](#__codelineno-0-56) | None = None, [](#__codelineno-0-57) _internal_lazy: bool = False, [](#__codelineno-0-58) _internal_preload: bool = False, [](#__codelineno-0-59))` Bases: `UIElement[list[str] | list[int] | list[dict[str, Any]], list[JSONType] | IntoDataFrame | list[TableCell]]` A table component with selectable rows. Get the selected rows with `table.value`. The table data can be supplied as: 1. a list of dicts, with one dict for each row, keyed by column names; 2. a list of values, representing a table with a single column; 3. a Pandas dataframe; or 4. a Polars dataframe; or 5. an Ibis dataframe; or 6. a PyArrow table. Examples: Create a table from a list of dicts, one for each row: `[](#__codelineno-0-1)table = mo.ui.table( [](#__codelineno-0-2) data=[ [](#__codelineno-0-3) {"first_name": "Michael", "last_name": "Scott"}, [](#__codelineno-0-4) {"first_name": "Dwight", "last_name": "Schrute"}, [](#__codelineno-0-5) ], [](#__codelineno-0-6) label="Users", [](#__codelineno-0-7))` Create a table from a single column of data: `[](#__codelineno-1-1)table = mo.ui.table( [](#__codelineno-1-2) data=[ [](#__codelineno-1-3) {"first_name": "Michael", "last_name": "Scott"}, [](#__codelineno-1-4) {"first_name": "Dwight", "last_name": "Schrute"}, [](#__codelineno-1-5) ], [](#__codelineno-1-6) label="Users", [](#__codelineno-1-7))` Create a table from a dataframe: `[](#__codelineno-2-1)# df is a Pandas or Polars dataframe [](#__codelineno-2-2)table = mo.ui.table( [](#__codelineno-2-3) data=df, [](#__codelineno-2-4) # use pagination when your table has many rows [](#__codelineno-2-5) pagination=True, [](#__codelineno-2-6) label="Dataframe", [](#__codelineno-2-7))` Create a table with format mapping: `[](#__codelineno-3-1)# format_mapping is a dict keyed by column names, [](#__codelineno-3-2)# with values as formatting functions or strings [](#__codelineno-3-3)def format_name(name): [](#__codelineno-3-4) return name.upper() [](#__codelineno-3-5) [](#__codelineno-3-6)[](#__codelineno-3-7)table = mo.ui.table( [](#__codelineno-3-8) data=[ [](#__codelineno-3-9) {"first_name": "Michael", "last_name": "Scott", "age": 45}, [](#__codelineno-3-10) {"first_name": "Dwight", "last_name": "Schrute", "age": 40}, [](#__codelineno-3-11) ], [](#__codelineno-3-12) format_mapping={ [](#__codelineno-3-13) "first_name": format_name, # Use callable to format first names [](#__codelineno-3-14) "age": "{:.1f}".format, # Use string format for age [](#__codelineno-3-15) }, [](#__codelineno-3-16) label="Format Mapping", [](#__codelineno-3-17))` Create a table with conditional cell formatting: `[](#__codelineno-4-1)import random [](#__codelineno-4-2) [](#__codelineno-4-3)[](#__codelineno-4-4)# rowId and columnName are strings. [](#__codelineno-4-5)def style_cell(_rowId, _columnName, value): [](#__codelineno-4-6) # Apply inline styling to the visible individual cells. [](#__codelineno-4-7) return { [](#__codelineno-4-8) "backgroundColor": "lightcoral" [](#__codelineno-4-9) if value < 4 [](#__codelineno-4-10) else "cornflowerblue", [](#__codelineno-4-11) "color": "white", [](#__codelineno-4-12) "fontStyle": "italic", [](#__codelineno-4-13) } [](#__codelineno-4-14) [](#__codelineno-4-15)[](#__codelineno-4-16)table = mo.ui.table( [](#__codelineno-4-17) data=[random.randint(0, 10) for x in range(200)], [](#__codelineno-4-18) style_cell=style_cell, [](#__codelineno-4-19)) [](#__codelineno-4-20)table` Create a table with per-cell hover text (plain text only): `[](#__codelineno-5-1)import random [](#__codelineno-5-2) [](#__codelineno-5-3)[](#__codelineno-5-4)# rowId and columnName are strings. [](#__codelineno-5-5)def hover_cell(rowId, columnName, value): [](#__codelineno-5-6) # Compute a short plain-text title for the visible individual cells. [](#__codelineno-5-7) return f"Row {rowId} — {columnName}: {value}" [](#__codelineno-5-8) [](#__codelineno-5-9)[](#__codelineno-5-10)table = mo.ui.table( [](#__codelineno-5-11) data=[random.randint(0, 10) for _ in range(200)], [](#__codelineno-5-12) hover_template=hover_cell, [](#__codelineno-5-13)) [](#__codelineno-5-14)table` In each case, access the table data with `table.value`. | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.table.value " value property writable (marimo.ui.table.value)")` | The selected rows, in the same format as the original data, or None if no selection. **TYPE:** `List[JSONType] | IntoDataFrame` | | `[data](#marimo.ui.table.data " data property (marimo.ui.table.data)")` | The original table data. **TYPE:** `List[JSONType] | IntoDataFrame` | | PARAMETER | DESCRIPTION | | --- | --- | | `data` | Values can be primitives (`str`, `int`, `float`, `bool`, or `None`) or marimo elements: e.g. `mo.ui.button(...)`, `mo.md(...)`, `mo.as_html(...)`, etc. Data can be passed in many ways: - as dataframes: a pandas dataframe, a polars dataframe - as rows: a list of dicts, where each dict represents a row in the table - as columns: a dict keyed by column names, where the value of each entry is a list representing a column - as a single column: a list of values **TYPE:** `List[str | int | float | bool | MIME | None] | List[Dict[str, JSONType]] | Dict[str, List[JSONType]] | IntoDataFrame` | | `pagination` | Whether to paginate; if False, all rows will be shown. Defaults to True when above 10 rows, False otherwise. **TYPE:** `bool` **DEFAULT:** `None` | | `selection` | 'single' or 'multi' to enable row selection, 'single-cell' or 'multi-cell' to enable cell selection or None to disable. Defaults to "multi". **TYPE:** `Literal['single', 'multi', 'single-cell', 'multi-cell']` **DEFAULT:** `'multi'` | | `initial_selection` | Indices of the rows you want selected by default. **TYPE:** `Union[List[int], List[tuple[str, str]]` **DEFAULT:** `None` | | `page_size` | The number of rows to show per page. Defaults to 10. **TYPE:** `int` **DEFAULT:** `None` | | `show_column_summaries` | Whether to show column summaries. Defaults to True when the table has less than 40 columns and at least 10 rows, False otherwise. If "stats", only show stats. If "chart", only show charts. **TYPE:** `bool | Literal['stats', 'chart']` **DEFAULT:** `None` | | `show_data_types` | Whether to show data types of columns in the table header. Defaults to True. **TYPE:** `bool` **DEFAULT:** `True` | | `show_download` | Whether to show the download button. Defaults to True for dataframes, False otherwise. **TYPE:** `bool` **DEFAULT:** `True` | | `format_mapping` | A mapping from column names to formatting strings or functions. **TYPE:** `Dict[str, str | Callable[..., Any]]` **DEFAULT:** `None` | | `freeze_columns_left` | List of column names to freeze on the left. **TYPE:** `Sequence[str]` **DEFAULT:** `None` | | `freeze_columns_right` | List of column names to freeze on the right. **TYPE:** `Sequence[str]` **DEFAULT:** `None` | | `text_justify_columns` | Dictionary of column names to text justification options: left, center, right. **TYPE:** `Dict[str, Literal['left', 'center', 'right']]` **DEFAULT:** `None` | | `wrapped_columns` | List of column names to wrap. **TYPE:** `List[str]` **DEFAULT:** `None` | | `header_tooltip` | Mapping from column names to tooltip text on the column header. **TYPE:** `Dict[str, str]` **DEFAULT:** `None` | | `label` | Markdown label for the element. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | `on_change` | Optional callback to run when this element's value changes. **TYPE:** `Callable[[Union[List[JSONType], Dict[str, List[JSONType]], IntoDataFrame, List[TableCell]]], None]` **DEFAULT:** `None` | | `style_cell` | A function that takes the row id, column name and value and returns a dictionary of CSS styles. **TYPE:** `Callable[[str, str, Any], Dict[str, Any]]` **DEFAULT:** `None` | | `hover_template` | Either a string template applied at the row level, or a callable that computes plain-text hover titles for individual visible cells. When a callable is provided, values are computed per page in Python and passed to the frontend; native HTML `title` is used for display. Plain text only is supported. **TYPE:** `str | Callable[[str, str, Any], str]` **DEFAULT:** `None` | | `max_columns` | Maximum number of columns to display. Defaults to the configured default\_table\_max\_columns (50 by default). Set to None to show all columns. **TYPE:** `int` **DEFAULT:** `MAX_COLUMNS_NOT_PROVIDED` | | `max_height` | Maximum height of the table body in pixels. When set, the table becomes vertically scrollable and the header will be made sticky in the UI to remain visible while scrolling. Defaults to None. **TYPE:** `int` **DEFAULT:** `None` | | `label` | A descriptive name for the table. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | ### data `property` [¶](#marimo.ui.table.data "Permanent link") Get the original table data. | RETURNS | DESCRIPTION | | --- | --- | | `TableData` | The original data passed to the table constructor, in its original format (list, dict, dataframe, etc.). **TYPE:** `TableData` | ### default\_page\_size `cached` `property` [¶](#marimo.ui.table.default_page_size "Permanent link") ### text `property` [¶](#marimo.ui.table.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.table.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.table.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.table.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.table.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.table.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.table.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### lazy `staticmethod` [¶](#marimo.ui.table.lazy "Permanent link") `[](#__codelineno-0-1)lazy( [](#__codelineno-0-2) data: IntoLazyFrame, [](#__codelineno-0-3) *, [](#__codelineno-0-4) page_size: int | None = None, [](#__codelineno-0-5) preload: bool = False, [](#__codelineno-0-6)) -> [table](#marimo.ui.table " marimo.ui.table (marimo._plugins.ui._impl.table.table)")` Create a table from a Polars LazyFrame. This won't load the data into memory until requested by the user. Once requested, only the first 10 rows will be loaded. Pagination and selection are not supported for lazy tables. | PARAMETER | DESCRIPTION | | --- | --- | | `data` | The data to display. **TYPE:** `IntoLazyFrame` | | `page_size` | The number of rows to show per page. **TYPE:** `int` **DEFAULT:** `None` | | `preload` | Whether to load the first page of data without user confirmation. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | ### left [¶](#marimo.ui.table.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.table.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.table.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Tabs - marimo https://docs.marimo.io/api/inputs/tabs/ Source code for `examples/ui/tabs.py` Tip: paste this code into an empty cell, and the marimo editor will create cells for you `import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(mo): tabs = mo.ui.tabs({ "Bob says": mo.md("Hello, Alice! 👋"), "Alice says": mo.md("Hello, Bob! 👋") }) tabs return (tabs,) @app.cell def _(tabs): tabs.value return if __name__ == "__main__": app.run()` marimo.ui.tabs [¶](#marimo.ui.tabs "Permanent link") ---------------------------------------------------- `[](#__codelineno-0-1)tabs( [](#__codelineno-0-2) tabs: dict[str, object], [](#__codelineno-0-3) value: str | None = None, [](#__codelineno-0-4) lazy: bool = False, [](#__codelineno-0-5) *, [](#__codelineno-0-6) label: str = "", [](#__codelineno-0-7) on_change: Callable[[str], None] | None = None, [](#__codelineno-0-8))` Bases: `UIElement[str, str]` Display objects in a tabbed view. Examples: Show content in tabs: `[](#__codelineno-0-1)tab1 = mo.vstack([mo.ui.slider(1, 10), mo.ui.text(), mo.ui.date()]) [](#__codelineno-0-2)[](#__codelineno-0-3)tab2 = mo.md("You can show arbitrary content in a tab.") [](#__codelineno-0-4)[](#__codelineno-0-5)tabs = mo.ui.tabs({"Heading 1": tab1, "Heading 2": tab2})` Control which tab is selected: `[](#__codelineno-1-1)tabs = mo.ui.tabs( [](#__codelineno-1-2) {"Heading 1": tab1, "Heading 2": tab2}, value="Heading 2" [](#__codelineno-1-3))` Tab content can be lazily loaded: `[](#__codelineno-2-1)tabs = mo.ui.tabs( [](#__codelineno-2-2) {"Heading 1": tab1, "Heading 2": expensive_component}, lazy=True [](#__codelineno-2-3))` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.tabs.value " value property writable (marimo.ui.tabs.value)")` | The name of the selected tab. **TYPE:** `str` | | PARAMETER | DESCRIPTION | | --- | --- | | `tabs` | A dictionary of tab names to tab content; strings are interpreted as markdown. **TYPE:** `dict[str, object]` | | `value` | The name of the tab to open. Defaults to the first tab. **TYPE:** `str` **DEFAULT:** `None` | | `lazy` | Whether to lazily load the tab content. This is a convenience that wraps each tab in a `mo.lazy` component. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `label` | A descriptive name for the tab. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | `on_change` | Optional callback to run when this element's value changes. **TYPE:** `Callable[[dict[str, object]], None]` **DEFAULT:** `None` | ### text `property` [¶](#marimo.ui.tabs.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.tabs.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.tabs.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.tabs.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.tabs.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.tabs.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.tabs.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### left [¶](#marimo.ui.tabs.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.tabs.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.tabs.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Control Flow - marimo https://docs.marimo.io/api/control_flow/ Controlling when cells run[¶](#controlling-when-cells-run "Permanent link") --------------------------------------------------------------------------- * Use [`mo.stop`](#marimo.stop " marimo.stop") to halt execution of a cell when a condition is met. * Combine [`mo.stop`](#marimo.stop " marimo.stop") with [`mo.ui.run_button`](https://docs.marimo.io/api/inputs/run_button/#marimo.ui.run_button " marimo.ui.run_button") to gate execution on button click. * Use [`mo.ui.refresh`](https://docs.marimo.io/api/inputs/refresh/#marimo.ui.refresh " marimo.ui.refresh") to make cells run periodically. marimo.stop [¶](#marimo.stop "Permanent link") ---------------------------------------------- `[](#__codelineno-0-1)stop(predicate: bool, output: object | None = None) -> None` Stops execution of a cell when `predicate` is `True` When `predicate` is `True`, this function raises a `MarimoStopError`. If uncaught, this exception stops execution of the current cell and makes `output` its output. Any descendants of this cell that were previously scheduled to run will not be run, and their defs will be removed from program memory. Examples: `[](#__codelineno-0-1)mo.stop(form.value is None, mo.md("**Submit the form to continue.**"))` | PARAMETER | DESCRIPTION | | --- | --- | | `predicate` | The predicate indicating whether to stop. **TYPE:** `bool` | | `output` | The output to be assigned to the current cell. **TYPE:** `bool` **DEFAULT:** `None` | | RAISES | DESCRIPTION | | --- | --- | | `MarimoStopError` | When `predicate` is `True` | Threading[¶](#threading "Permanent link") ----------------------------------------- marimo.Thread [¶](#marimo.Thread "Permanent link") -------------------------------------------------- `[](#__codelineno-0-1)Thread(*args: Any, **kwargs: Any)` Bases: `Thread` A Thread subclass that can communicate with the frontend. `mo.Thread` has the same API as threading.Thread, but `mo.Thread`s are able to communicate with the marimo frontend, whereas `threading.Thread` can't. Threads can append to a cell's output using `mo.output.append`, or to the console output area using `print`. The corresponding outputs will be forwarded to the frontend. Writing directly to sys.stdout or sys.stderr, or to file descriptors 1 and 2, is not yet supported. **Thread lifecycle.** When the cell that spawned this thread is invalidated (re-run, deleted, interrupted, or otherwise errored), this thread's `should_exit` property will evaluate to `True`, at which point it is the developer's responsibility to clean up their thread. Examples: `[](#__codelineno-0-1)def target(): [](#__codelineno-0-2) import time [](#__codelineno-0-3) import marimo as mo [](#__codelineno-0-4) [](#__codelineno-0-5) thread = mo.current_thread() [](#__codelineno-0-6) while not thread.should_exit: [](#__codelineno-0-7) time.sleep(1) [](#__codelineno-0-8) print("hello")` `[](#__codelineno-1-1)import marimo as mo [](#__codelineno-1-2)[](#__codelineno-1-3)mo.Thread(target=target).start()` ### should\_exit `property` [¶](#marimo.Thread.should_exit "Permanent link") Whether this thread should exit. Returns `True` when the cell that spawned this thread has been invalidated; for example, if the cell: * was re-run * was deleted * was interrupted then this property evaluates to True. It is the developer's responsibility to clean up and finish their thread when this flag is set. Retrieve the current `mo.Thread` with `[](#__codelineno-0-1)import marimo as mo [](#__codelineno-0-2)[](#__codelineno-0-3)mo.current_thread()` ### run [¶](#marimo.Thread.run "Permanent link") marimo.current\_thread [¶](#marimo.current_thread "Permanent link") ------------------------------------------------------------------- `[](#__codelineno-0-1)current_thread() -> [Thread](#marimo.Thread " marimo.Thread (marimo._runtime.threads.Thread)")` Return the `marimo.Thread` object for the caller's thread of control. | RETURNS | DESCRIPTION | | --- | --- | | `[Thread](#marimo.Thread " marimo.Thread (marimo._runtime.threads.Thread)")` | The current `marimo.Thread` object. | | RAISES | DESCRIPTION | | --- | --- | | `RuntimeError` | If the current thread of control is not a `marimo.Thread`. | Text - marimo https://docs.marimo.io/api/inputs/text/ marimo.ui.text [¶](#marimo.ui.text "Permanent link") ---------------------------------------------------- `[](#__codelineno-0-1)text( [](#__codelineno-0-2) value: str = "", [](#__codelineno-0-3) placeholder: str = "", [](#__codelineno-0-4) kind: Literal[ [](#__codelineno-0-5) "text", "password", "email", "url" [](#__codelineno-0-6) ] = "text", [](#__codelineno-0-7) max_length: int | None = None, [](#__codelineno-0-8) disabled: bool = False, [](#__codelineno-0-9) debounce: bool | int = True, [](#__codelineno-0-10) *, [](#__codelineno-0-11) label: str = "", [](#__codelineno-0-12) on_change: Callable[[str], None] | None = None, [](#__codelineno-0-13) full_width: bool = False, [](#__codelineno-0-14))` Bases: `UIElement[str, str]` A text input. Examples: `[](#__codelineno-0-1)text = mo.ui.text(value="Hello, World!")` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.text.value " value property writable (marimo.ui.text.value)")` | A string of the input's contents. **TYPE:** `str` | | PARAMETER | DESCRIPTION | | --- | --- | | `value` | Default value of text box. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | `placeholder` | Placeholder text to display when the text area is empty. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | `kind` | Input kind. Defaults to "text". **TYPE:** `Literal['text', 'password', 'email', 'url']` **DEFAULT:** `'text'` | | `max_length` | Maximum length of input. Defaults to None. **TYPE:** `int` **DEFAULT:** `None` | | `disabled` | Whether the input is disabled. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `debounce` | Whether the input is debounced. If number, debounce by that many milliseconds. If True, then value is only emitted on Enter or when the input loses focus. Defaults to True. **TYPE:** `bool | int` **DEFAULT:** `True` | | `label` | Markdown label for the element. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[str], None]` **DEFAULT:** `None` | | `full_width` | Whether the input should take up the full width of its container. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | ### text `property` [¶](#marimo.ui.text.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.text.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.text.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.text.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.text.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.text.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.text.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### left [¶](#marimo.ui.text.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.text.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.text.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Layouts - marimo https://docs.marimo.io/api/layouts/ marimo has higher-order layout functions that you can use to arrange outputs in rows, columns, tables, tabs, and more. Stateless[¶](#stateless "Permanent link") ----------------------------------------- Unlike elements in `marimo.ui`, these don't have any values associated with them but just render their children in a certain way. | Function | Description | | --- | --- | | [`marimo.accordion`](https://docs.marimo.io/api/layouts/accordion/#marimo.accordion " marimo.accordion") | Create collapsible sections | | [`marimo.carousel`](https://docs.marimo.io/api/layouts/carousel/#marimo.carousel " marimo.carousel") | Create a slideshow | | [`marimo.callout`](https://docs.marimo.io/api/layouts/callout/#marimo.callout " marimo.callout") | Create highlighted sections | | [`marimo.center`](https://docs.marimo.io/api/layouts/justify/#marimo.center " marimo.center") | Center content | | [`marimo.hstack`](https://docs.marimo.io/api/layouts/stacks/#marimo.hstack " marimo.hstack") | Stack elements horizontally | | [`marimo.lazy`](https://docs.marimo.io/api/layouts/lazy/#marimo.lazy " marimo.lazy") | Lazy load content | | [`marimo.left`](https://docs.marimo.io/api/layouts/justify/#marimo.left " marimo.left") | Left-align content | | [`marimo.nav_menu`](https://docs.marimo.io/api/inputs/nav_menu/#marimo.nav_menu " marimo.nav_menu") | Create navigation menus | | [`marimo.outline`](https://docs.marimo.io/api/layouts/outline/#marimo.outline " marimo.outline") | Display table of contents outline | | [`marimo.plain`](https://docs.marimo.io/api/layouts/plain/#marimo.plain " marimo.plain") | Display content without styling | | [`marimo.right`](https://docs.marimo.io/api/layouts/justify/#marimo.right " marimo.right") | Right-align content | | [`marimo.routes`](https://docs.marimo.io/api/layouts/routes/#marimo.routes " marimo.routes") | Create page routing | | [`marimo.stat`](https://docs.marimo.io/api/layouts/stat/#marimo.stat " marimo.stat") | Display statistics | | [`marimo.sidebar`](https://docs.marimo.io/api/layouts/sidebar/#marimo.sidebar " marimo.sidebar") | Create sidebars | | [`marimo.tree`](https://docs.marimo.io/api/layouts/tree/#marimo.tree " marimo.tree") | Create tree structures | | [`marimo.json`](https://docs.marimo.io/api/layouts/json/#marimo.json " marimo.json") | Create JSON structures | | [`marimo.vstack`](https://docs.marimo.io/api/layouts/stacks/#marimo.vstack " marimo.vstack") | Stack elements vertically | Stateful[¶](#stateful "Permanent link") --------------------------------------- Some elements in `marimo.ui` are also helpful for layout. These elements do have values associated with them: for example, `tabs` tracks the selected tab name, and `table` tracks the selected rows. | Function | Description | | --- | --- | | [`marimo.ui.tabs`](https://docs.marimo.io/api/inputs/tabs/#marimo.ui.tabs " marimo.ui.tabs") | Create tabbed interfaces | | [`marimo.ui.table`](https://docs.marimo.io/api/inputs/table/#marimo.ui.table " marimo.ui.table") | Create interactive tables | Text Area - marimo https://docs.marimo.io/api/inputs/text_area/ Source code for `examples/ui/text_area.py` Tip: paste this code into an empty cell, and the marimo editor will create cells for you `import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(mo): text_area = mo.ui.text_area(placeholder="type some text ...") text_area return (text_area,) @app.cell def _(text_area): text_area.value return if __name__ == "__main__": app.run()` marimo.ui.text\_area [¶](#marimo.ui.text_area "Permanent link") --------------------------------------------------------------- `[](#__codelineno-0-1)text_area( [](#__codelineno-0-2) value: str = "", [](#__codelineno-0-3) placeholder: str = "", [](#__codelineno-0-4) max_length: int | None = None, [](#__codelineno-0-5) disabled: bool = False, [](#__codelineno-0-6) debounce: bool | int = True, [](#__codelineno-0-7) rows: int | None = None, [](#__codelineno-0-8) *, [](#__codelineno-0-9) label: str = "", [](#__codelineno-0-10) on_change: Callable[[str], None] | None = None, [](#__codelineno-0-11) full_width: bool = False, [](#__codelineno-0-12))` Bases: `UIElement[str, str]` A text area that is larger than `ui.text`. Examples: `[](#__codelineno-0-1)text_area = mo.ui.text_area()` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.text_area.value " value property writable (marimo.ui.text_area.value)")` | A string of the text area contents. **TYPE:** `str` | | PARAMETER | DESCRIPTION | | --- | --- | | `value` | Initial value of the text area. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | `placeholder` | Placeholder text to display when the text area is empty. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | `max_length` | Maximum length of input. Defaults to None. **TYPE:** `int` **DEFAULT:** `None` | | `disabled` | Whether the input is disabled. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `debounce` | Whether the input is debounced. If number, debounce by that many milliseconds. If True, then value is only emitted on Ctrl+Enter or when the input loses focus. Defaults to True. **TYPE:** `bool | int` **DEFAULT:** `True` | | `rows` | Number of rows of text to display. Defaults to None. **TYPE:** `int` **DEFAULT:** `None` | | `label` | Markdown label for the element. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[str], None]` **DEFAULT:** `None` | | `full_width` | Whether the input should take up the full width of its container. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | ### text `property` [¶](#marimo.ui.text_area.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.text_area.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.text_area.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.text_area.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.text_area.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.text_area.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.text_area.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### left [¶](#marimo.ui.text_area.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.text_area.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.text_area.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Accordion - marimo https://docs.marimo.io/api/layouts/accordion/ Source code for `examples/outputs/accordion.py` Tip: paste this code into an empty cell, and the marimo editor will create cells for you `import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(mo): mo.accordion( { "Door 1": mo.md("Nothing!"), "Door 2": mo.md("Nothing!"), "Door 3": mo.md( "![goat](https://images.unsplash.com/photo-1524024973431-2ad916746881)" ), } ) return if __name__ == "__main__": app.run()` marimo.accordion [¶](#marimo.accordion "Permanent link") -------------------------------------------------------- `[](#__codelineno-0-1)accordion( [](#__codelineno-0-2) items: dict[str, object], [](#__codelineno-0-3) multiple: bool = False, [](#__codelineno-0-4) lazy: bool = False, [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Accordion of one or more items. | PARAMETER | DESCRIPTION | | --- | --- | | `items` | a dictionary of item names to item content; strings are interpreted as markdown **TYPE:** `dict[str, object]` | | `multiple` | whether to allow multiple items to be open simultaneously **TYPE:** `bool` **DEFAULT:** `False` | | `lazy` | a boolean, whether to lazily load the accordion content. This is a convenience that wraps each accordion in a `mo.lazy` component. **TYPE:** `bool` **DEFAULT:** `False` | | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | Example `[](#__codelineno-0-1)mo.accordion( [](#__codelineno-0-2) {"Tip": "Use accordions to let users reveal and hide content."} [](#__codelineno-0-3))` Accordion content can be lazily loaded: `[](#__codelineno-1-1)mo.accordion({"View total": expensive_item}, lazy=True)` where `expensive_item` is the item to render, or a callable that returns the item to render. Callout - marimo https://docs.marimo.io/api/layouts/callout/ marimo.callout [¶](#marimo.callout "Permanent link") ---------------------------------------------------- `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) value: object, [](#__codelineno-0-3) kind: Literal[ [](#__codelineno-0-4) "neutral", "warn", "success", "info", "danger" [](#__codelineno-0-5) ] = "neutral", [](#__codelineno-0-6)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Build a callout output. | PARAMETER | DESCRIPTION | | --- | --- | | `value` | A value to render in the callout **TYPE:** `object` | | `kind` | The kind of callout (affects styling). **TYPE:** `Literal['neutral', 'warn', 'success', 'info', 'danger']` **DEFAULT:** `'neutral'` | | RETURNS | DESCRIPTION | | --- | --- | | `Html` | An HTML object. **TYPE:** `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass ")` | Carousel - marimo https://docs.marimo.io/api/layouts/carousel/ marimo.carousel [¶](#marimo.carousel "Permanent link") ------------------------------------------------------ `[](#__codelineno-0-1)carousel(items: Sequence[object]) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a carousel of items. | PARAMETER | DESCRIPTION | | --- | --- | | `items` | A list of items. **TYPE:** `Sequence[object]` | | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | Example `[](#__codelineno-0-1)mo.carousel([mo.md("..."), mo.ui.text_area()])` Justify - marimo https://docs.marimo.io/api/layouts/justify/ marimo.center [¶](#marimo.center "Permanent link") -------------------------------------------------- `[](#__codelineno-0-1)center(item: object) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Center an item. | PARAMETER | DESCRIPTION | | --- | --- | | `item` | object to center. **TYPE:** `object` | | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | A centered `Html` object. | marimo.left [¶](#marimo.left "Permanent link") ---------------------------------------------- `[](#__codelineno-0-1)left(item: object) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Left-justify an item. | PARAMETER | DESCRIPTION | | --- | --- | | `item` | object to left-justify. **TYPE:** `object` | | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | A left-justified `Html` object. | marimo.right [¶](#marimo.right "Permanent link") ------------------------------------------------ `[](#__codelineno-0-1)right(item: object) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Right-justify an item. | PARAMETER | DESCRIPTION | | --- | --- | | `item` | object to right-justify. **TYPE:** `object` | | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | A right-justified `Html` object. | Json - marimo https://docs.marimo.io/api/layouts/json/ marimo.json [¶](#marimo.json "Permanent link") ---------------------------------------------- `[](#__codelineno-0-1)json( [](#__codelineno-0-2) data: str | dict[str, Any] | list[Any], [](#__codelineno-0-3) label: str | None = None, [](#__codelineno-0-4)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Render a JSON with tree. Example `[](#__codelineno-0-1)mo.json( [](#__codelineno-0-2) '["entry", "another entry", {"key": [0, 1, 2]}]', [](#__codelineno-0-3) label="A JSON in tree.", [](#__codelineno-0-4))` | PARAMETER | DESCRIPTION | | --- | --- | | `data` | JSON string or JSON-compatible Python object(s) to render **TYPE:** `str | dict[str, Any] | list[Any]` | | `label` | optional text label for the tree **TYPE:** `str | None` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | --- | --- | | `Html` | `Html` object **TYPE:** `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | Outline - marimo https://docs.marimo.io/api/layouts/outline/ Display a table of contents outline showing all markdown headers in the notebook. The outline automatically extracts all markdown headers from executed cells and displays them in a hierarchical structure with clickable navigation. Examples: Basic outline: With custom label: `[](#__codelineno-1-1)mo.outline(label="Table of Contents")` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A descriptive label for the outline. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | RETURNS | DESCRIPTION | | --- | --- | | `Html` | An HTML object that renders the outline component. **TYPE:** `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | Lazy - marimo https://docs.marimo.io/api/layouts/lazy/ marimo.lazy [¶](#marimo.lazy "Permanent link") ---------------------------------------------- `[](#__codelineno-0-1)lazy( [](#__codelineno-0-2) element: Callable[[], object] [](#__codelineno-0-3) | object [](#__codelineno-0-4) | Callable[[], Coroutine[None, None, object]], [](#__codelineno-0-5) show_loading_indicator: bool = False, [](#__codelineno-0-6))` Bases: `UIElement[bool, bool]` Lazy load a component until it is visible. Use `mo.lazy` to defer rendering of an item until it's visible. This is useful for loading expensive components only when they are needed, e.g., only when an accordion or tab is opened. The argument to `mo.lazy` can be an object to render lazily, or a function that returns the object to render (that is, functions are lazily evaluated). The function can be synchronous or asynchronous. Using a function is useful when the item to render is the result of a database query or some other expensive operation. Examples: Create a lazy-loaded tab: `[](#__codelineno-0-1)tabs = mo.ui.tabs( [](#__codelineno-0-2) {"Overview": tab1, "Charts": mo.lazy(expensive_component)} [](#__codelineno-0-3))` Create a lazy-loaded accordion: `[](#__codelineno-1-1)accordion = mo.accordion({"Charts": mo.lazy(expensive_component)})` Usage with async functions: `[](#__codelineno-2-1)async def expensive_component(): ... [](#__codelineno-2-2) [](#__codelineno-2-3)[](#__codelineno-2-4)mo.lazy(expensive_component)` | PARAMETER | DESCRIPTION | | --- | --- | | `element` | Object or callable that returns content to be lazily loaded. **TYPE:** `Callable[[], object] | object | Callable[[], Coroutine[None, None, object]]` | | `show_loading_indicator` | Whether to show a loading indicator while the content is being loaded. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | ### text `property` [¶](#marimo.lazy.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.lazy.value "Permanent link") The element's current value. ### batch [¶](#marimo.lazy.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.lazy.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.lazy.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.lazy.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.lazy.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### left [¶](#marimo.lazy.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.lazy.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.lazy.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Plain - marimo https://docs.marimo.io/api/layouts/plain/ marimo.plain [¶](#marimo.plain "Permanent link") ------------------------------------------------ `[](#__codelineno-0-1)plain(value: Any) -> Plain` Wrap a value to indicate that it should be displayed without any opinionated formatting. This is the best way to opt out of marimo's default dataframe rendering. Example `[](#__codelineno-0-1)df = data.cars() [](#__codelineno-0-2)mo.plain(df)` | PARAMETER | DESCRIPTION | | --- | --- | | `value` | Any value **TYPE:** `Any` | Routes - marimo https://docs.marimo.io/api/layouts/routes/ marimo.routes [¶](#marimo.routes "Permanent link") -------------------------------------------------- `[](#__codelineno-0-1)routes( [](#__codelineno-0-2) routes: dict[ [](#__codelineno-0-3) str, [](#__codelineno-0-4) Callable[[], object] [](#__codelineno-0-5) | Callable[[], Coroutine[None, None, object]] [](#__codelineno-0-6) | object, [](#__codelineno-0-7) ], [](#__codelineno-0-8))` Bases: `UIElement[str, str]` Renders a list of routes that are switched based on the URL path. Routes currently don't support nested routes, or dynamic routes (e.g. `#/user/:id`). If you'd like to see these features, please let us know on GitHub: [https://github.com/marimo-team/marimo/issues](https://github.com/marimo-team/marimo/issues) For a simple-page-application (SPA) experience, you should use hash-based routing. For example, prefix your routes with `#/`. If you are using a multi-page-application (MPA) with `marimo.create_asgi_app`, you should use path-based routing. For example, prefix your routes with `/`. Examples: `[](#__codelineno-0-1)mo.routes( [](#__codelineno-0-2) { [](#__codelineno-0-3) "#/": render_home, [](#__codelineno-0-4) "#/about": render_about, [](#__codelineno-0-5) "#/contact": render_contact, [](#__codelineno-0-6) mo.routes.CATCH_ALL: render_home, [](#__codelineno-0-7) } [](#__codelineno-0-8))` | PARAMETER | DESCRIPTION | | --- | --- | | `routes` | A dictionary of routes, where the key is the URL path and the value is a function that returns the content to display. **TYPE:** `dict[str, Callable[[], object] | Callable[[], Coroutine[None, None, object]] | object]` | | RETURNS | DESCRIPTION | | --- | --- | | `Html` | An Html object. **TYPE:** `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass ")` | ### CATCH\_ALL `class-attribute` `instance-attribute` [¶](#marimo.routes.CATCH_ALL "Permanent link") ### DEFAULT `class-attribute` `instance-attribute` [¶](#marimo.routes.DEFAULT "Permanent link") ### text `property` [¶](#marimo.routes.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.routes.value "Permanent link") The element's current value. ### batch [¶](#marimo.routes.batch "Permanent link") `[](#__codelineno-0-1)batch(*args: Any, **kwargs: Any) -> Any` ### callout [¶](#marimo.routes.callout "Permanent link") `[](#__codelineno-0-1)callout(*args: Any, **kwargs: Any) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` ### center [¶](#marimo.routes.center "Permanent link") `[](#__codelineno-0-1)center(*args: Any, **kwargs: Any) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` ### form [¶](#marimo.routes.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.routes.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### left [¶](#marimo.routes.left "Permanent link") `[](#__codelineno-0-1)left(*args: Any, **kwargs: Any) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` ### right [¶](#marimo.routes.right "Permanent link") `[](#__codelineno-0-1)right(*args: Any, **kwargs: Any) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` ### style [¶](#marimo.routes.style "Permanent link") `[](#__codelineno-0-1)style(*args: Any, **kwargs: Any) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` python import marimo app = marimo.App() @app.cell def \_\_(): import marimo as mo return @app.cell def \_\_(): mo.sidebar( \[ mo.md("# marimo"), mo.nav\_menu( { "#/": f"{mo.icon('lucide:home')} Home", "#/about": f"{mo.icon('lucide:user')} About", "#/contact": f"{mo.icon('lucide:phone')} Contact", "Links": { "[https://twitter.com/marimo\_io](https://twitter.com/marimo_io)": "Twitter", "[https://github.com/marimo-team/marimo](https://github.com/marimo-team/marimo)": "GitHub", }, }, orientation="vertical", ), \] ) return @app.cell def \_\_(): mo.routes({ "#/": mo.md("# Home"), "#/about": mo.md("# About"), "#/contact": mo.md("# Contact"), mo.routes.CATCH\_ALL: mo.md("# Home"), }) return Sidebar - marimo https://docs.marimo.io/api/layouts/sidebar/ `[](#__codelineno-0-1)sidebar( [](#__codelineno-0-2) item: object, [](#__codelineno-0-3) footer: object | None = None, [](#__codelineno-0-4) *, [](#__codelineno-0-5) width: str | int | None = None, [](#__codelineno-0-6))` Bases: `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Displays content in a sidebar. This is a special layout component that will display the content in a sidebar layout, rather than below/above the cell. This component still needs to be the last expression in the cell, in order to display correctly. You may use more than one `mo.sidebar` - they will be displayed in the order they are called. Examples: `[](#__codelineno-0-1)mo.sidebar( [](#__codelineno-0-2) [ [](#__codelineno-0-3) mo.md("# marimo"), [](#__codelineno-0-4) mo.nav_menu( [](#__codelineno-0-5) { [](#__codelineno-0-6) "#home": f"{mo.icon('lucide:home')} Home", [](#__codelineno-0-7) "#about": f"{mo.icon('lucide:user')} About", [](#__codelineno-0-8) "#contact": f"{mo.icon('lucide:phone')} Contact", [](#__codelineno-0-9) "Links": { [](#__codelineno-0-10) "https://twitter.com/marimo_io": "Twitter", [](#__codelineno-0-11) "https://github.com/marimo-team/marimo": "GitHub", [](#__codelineno-0-12) }, [](#__codelineno-0-13) }, [](#__codelineno-0-14) orientation="vertical", [](#__codelineno-0-15) ), [](#__codelineno-0-16) ] [](#__codelineno-0-17))` | PARAMETER | DESCRIPTION | | --- | --- | | `item` | The content to display in the sidebar. **TYPE:** `object` | | `footer` | The content to display at the bottom of the sidebar. **TYPE:** `object` **DEFAULT:** `None` | | `width` | The width of the sidebar when open. Can be any valid CSS width value (e.g. "300px", "20rem"). If not provided, defaults to the standard width. **TYPE:** `str` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | --- | --- | | `Html` | An Html object. **TYPE:** `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass ")` | A string of HTML representing this element. `[](#__codelineno-0-1)batch(*args: Any, **kwargs: Any) -> Any` `[](#__codelineno-0-1)callout(*args: Any, **kwargs: Any) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` `[](#__codelineno-0-1)center(*args: Any, **kwargs: Any) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` `[](#__codelineno-0-1)left(*args: Any, **kwargs: Any) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` `[](#__codelineno-0-1)right(*args: Any, **kwargs: Any) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` `[](#__codelineno-0-1)style(*args: Any, **kwargs: Any) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Stat - marimo https://docs.marimo.io/api/layouts/stat/ marimo.stat [¶](#marimo.stat "Permanent link") ---------------------------------------------- `[](#__codelineno-0-1)stat( [](#__codelineno-0-2) value: str | int | float, [](#__codelineno-0-3) label: str | None = None, [](#__codelineno-0-4) caption: str | None = None, [](#__codelineno-0-5) direction: Literal["increase", "decrease"] [](#__codelineno-0-6) | None = None, [](#__codelineno-0-7) bordered: bool = False, [](#__codelineno-0-8) target_direction: Literal["increase", "decrease"] [](#__codelineno-0-9) | None = "increase", [](#__codelineno-0-10) slot: [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)") | None = None, [](#__codelineno-0-11)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Display a statistic. Optionally include a label, caption, and direction. | PARAMETER | DESCRIPTION | | --- | --- | | `value` | the value to display **TYPE:** `str | int | float` | | `label` | the label to display **TYPE:** `str | None` **DEFAULT:** `None` | | `caption` | the caption to display **TYPE:** `str | None` **DEFAULT:** `None` | | `direction` | the direction of the statistic, either `increase` or `decrease` **TYPE:** `Literal['increase', 'decrease'] | None` **DEFAULT:** `None` | | `bordered` | whether to display a border around the statistic **TYPE:** `bool` **DEFAULT:** `False` | | `target_direction` | the direction of the statistic corresponding to a positive or desirable outcome. Set to `increase` when higher values are better, or `decrease` when lower values are better. By default the target direction is `increase`. **TYPE:** `Literal['increase', 'decrease'] | None` **DEFAULT:** `'increase'` | | `slot` | an optional Html object to place beside the widget **TYPE:** `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)") | None` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object representing the statistic. | Stacks - marimo https://docs.marimo.io/api/layouts/stacks/ marimo.hstack [¶](#marimo.hstack "Permanent link") -------------------------------------------------- `[](#__codelineno-0-1)hstack( [](#__codelineno-0-2) items: Sequence[object], [](#__codelineno-0-3) *, [](#__codelineno-0-4) justify: Literal[ [](#__codelineno-0-5) "start", [](#__codelineno-0-6) "center", [](#__codelineno-0-7) "end", [](#__codelineno-0-8) "space-between", [](#__codelineno-0-9) "space-around", [](#__codelineno-0-10) ] = "space-between", [](#__codelineno-0-11) align: Literal["start", "end", "center", "stretch"] [](#__codelineno-0-12) | None = None, [](#__codelineno-0-13) wrap: bool = False, [](#__codelineno-0-14) gap: float = 0.5, [](#__codelineno-0-15) widths: Literal["equal"] [](#__codelineno-0-16) | Sequence[float] [](#__codelineno-0-17) | None = None, [](#__codelineno-0-18)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Stack items horizontally, in a row. Combine with `vstack` to build a grid. Examples: Build a row of items: `[](#__codelineno-0-1)# Build a row of items [](#__codelineno-0-2)mo.hstack([mo.md("..."), mo.ui.text_area()])` Build a row of items with equal width: `[](#__codelineno-1-1)mo.hstack([mo.md("..."), mo.ui.text_area()], widths="equal")` Have one item stretch to fill the available space, while another fits its content: `[](#__codelineno-2-1)mo.hstack( [](#__codelineno-2-2) [mo.plain_text("..."), mo.ui.text_area(full_width=True)], [](#__codelineno-2-3) widths=[0, 1], [](#__codelineno-2-4))` Build a grid: `[](#__codelineno-3-1)# Build a grid. [](#__codelineno-3-2)mo.hstack( [](#__codelineno-3-3) [ [](#__codelineno-3-4) mo.vstack([mo.md("..."), mo.ui.text_area()]), [](#__codelineno-3-5) mo.vstack([mo.ui.checkbox(), mo.ui.text(), mo.ui.date()]), [](#__codelineno-3-6) ] [](#__codelineno-3-7))` | PARAMETER | DESCRIPTION | | --- | --- | | `items` | A list of items. **TYPE:** `Sequence[object]` | | `justify` | Justify items horizontally: start, center, end, space-between, or space-around. Defaults to "space-between". **TYPE:** `Literal['start', 'center', 'end', 'space-between', 'space-around']` **DEFAULT:** `'space-between'` | | `align` | Align items vertically: start, end, center, or stretch. **TYPE:** `Literal['start', 'end', 'center', 'stretch'] | None` **DEFAULT:** `None` | | `wrap` | Wrap items or not. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `gap` | Gap between items as a float in rem. 1rem is 16px by default. Defaults to 0.5. **TYPE:** `float` **DEFAULT:** `0.5` | | `widths` | "equal" to give items equal width; or a list of relative widths with same length as `items`, eg, \[1, 2\] means the second item is twice as wide as the first; or None for a sensible default. **TYPE:** `Literal['equal'] | Sequence[float] | None` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | --- | --- | | `Html` | An Html object. **TYPE:** `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | marimo.vstack [¶](#marimo.vstack "Permanent link") -------------------------------------------------- `[](#__codelineno-0-1)vstack( [](#__codelineno-0-2) items: Sequence[object], [](#__codelineno-0-3) *, [](#__codelineno-0-4) align: Literal["start", "end", "center", "stretch"] [](#__codelineno-0-5) | None = None, [](#__codelineno-0-6) justify: Literal[ [](#__codelineno-0-7) "start", [](#__codelineno-0-8) "center", [](#__codelineno-0-9) "end", [](#__codelineno-0-10) "space-between", [](#__codelineno-0-11) "space-around", [](#__codelineno-0-12) ] = "start", [](#__codelineno-0-13) gap: float = 0.5, [](#__codelineno-0-14) heights: Literal["equal"] [](#__codelineno-0-15) | Sequence[float] [](#__codelineno-0-16) | None = None, [](#__codelineno-0-17)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Stack items vertically, in a column. Combine with `hstack` to build a grid of items. Examples: Build a column of items: `[](#__codelineno-0-1)# Build a column of items [](#__codelineno-0-2)mo.vstack([mo.md("..."), mo.ui.text_area()])` Build a grid: `[](#__codelineno-1-1)# Build a grid. [](#__codelineno-1-2)mo.vstack( [](#__codelineno-1-3) [ [](#__codelineno-1-4) mo.hstack([mo.md("..."), mo.ui.text_area()]), [](#__codelineno-1-5) mo.hstack([mo.ui.checkbox(), mo.ui.text(), mo.ui.date()]), [](#__codelineno-1-6) ] [](#__codelineno-1-7))` | PARAMETER | DESCRIPTION | | --- | --- | | `items` | A list of items. **TYPE:** `Sequence[object]` | | `align` | Align items horizontally: start, end, center, or stretch. **TYPE:** `Literal['start', 'end', 'center', 'stretch'] | None` **DEFAULT:** `None` | | `justify` | Justify items vertically: start, center, end, space-between, or space-around. Defaults to "start". **TYPE:** `Literal['start', 'center', 'end', 'space-between', 'space-around']` **DEFAULT:** `'start'` | | `gap` | Gap between items as a float in rem. 1rem is 16px by default. Defaults to 0.5. **TYPE:** `float` **DEFAULT:** `0.5` | | `heights` | "equal" to give items equal height; or a list of relative heights with same length as `items`, eg, \[1, 2\] means the second item is twice as tall as the first; or None for a sensible default. **TYPE:** `Literal['equal'] | Sequence[float] | None` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | --- | --- | | `Html` | An Html object. **TYPE:** `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | Media - marimo https://docs.marimo.io/api/media/ Use these functions to embed media in your outputs. | Function | Description | | --- | --- | | [`marimo.image`](https://docs.marimo.io/api/media/image/) | Display images | | [`marimo.image_compare`](https://docs.marimo.io/api/media/image_compare/) | Compare two images side by side | | [`marimo.audio`](https://docs.marimo.io/api/media/audio/) | Play audio files | | [`marimo.video`](https://docs.marimo.io/api/media/video/) | Play videos | | [`marimo.pdf`](https://docs.marimo.io/api/media/pdf/) | Display PDFs | | [`marimo.download`](https://docs.marimo.io/api/media/download/) | Create download links | | [`marimo.plain_text`](https://docs.marimo.io/api/media/plain_text/) | Display plain text | Most of these methods accept URLs (including data URLs), paths to local files, or file-like objects. Tree - marimo https://docs.marimo.io/api/layouts/tree/ marimo.tree [¶](#marimo.tree "Permanent link") ---------------------------------------------- `[](#__codelineno-0-1)tree( [](#__codelineno-0-2) items: list[Any] | tuple[Any] | dict[Any, Any], [](#__codelineno-0-3) label: str | None = None, [](#__codelineno-0-4)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Render a nested structure of lists, tuples, or dicts as a tree. Example `[](#__codelineno-0-1)mo.tree( [](#__codelineno-0-2) ["entry", "another entry", {"key": [0, 1, 2]}], label="A tree." [](#__codelineno-0-3))` | PARAMETER | DESCRIPTION | | --- | --- | | `items` | nested structure of lists, tuples, or dicts **TYPE:** `list[Any] | tuple[Any] | dict[Any, Any]` | | `label` | optional text label for the tree **TYPE:** `str | None` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | --- | --- | | `Html` | `Html` object **TYPE:** `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | Audio - marimo https://docs.marimo.io/api/media/audio/ `[](#__codelineno-0-1)audio( [](#__codelineno-0-2) src: str | BytesIO | NDArray[Any], [](#__codelineno-0-3) rate: int | None = None, [](#__codelineno-0-4) normalize: bool = True, [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Render an audio file as HTML. | PARAMETER | DESCRIPTION | | --- | --- | | `src` | a path or URL to an audio `file`, `bytes`, or a file-like object opened in binary mode, `1D numpy array` → Mono waveform, `2D numpy array` → Multi-channel waveform (Shape: `[NCHAN, NSAMPLES]`). **TYPE:** `str | BytesIO | NDArray[Any]` | | `rate` | Sampling rate (required only for NumPy arrays). **TYPE:** `int | None` **DEFAULT:** `None` | | `normalize` | Whether to rescale NumPy array audio to its max range (`True` by default). If `False`, values must be in `[-1, 1]`, or an error is raised. Does not apply to non-array audio sources. **TYPE:** `bool` **DEFAULT:** `True` | | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An audio player as an `Html` object. | Example `[](#__codelineno-0-1)mo.audio( [](#__codelineno-0-2) src="https://upload.wikimedia.org/wikipedia/commons/8/8c/Ivan_Ili%C4%87-Chopin_-_Prelude_no._1_in_C_major.ogg" [](#__codelineno-0-3)) [](#__codelineno-0-4)[](#__codelineno-0-5)mo.audio(src="path/to/local/file.wav")` Plotting - marimo https://docs.marimo.io/api/plotting/ marimo supports most major plotting libraries, including Matplotlib, Seaborn, Plotly, and Altair. Just import your plotting library of choice and use it as you normally would. For more information about plotting, see the [plotting guide](https://docs.marimo.io/guides/working_with_data/plotting/). Reactive plots with matplotlib[¶](#reactive-plots-with-matplotlib "Permanent link") ----------------------------------------------------------------------------------- marimo.ui.matplotlib [¶](#marimo.ui.matplotlib "Permanent link") ---------------------------------------------------------------- `[](#__codelineno-0-1)matplotlib(axes: Axes, *, debounce: bool = False)` Bases: `UIElement[dict[str, JSONType], MatplotlibSelection]` Make reactive selections on matplotlib plots. Use `mo.ui.matplotlib` to make matplotlib plots interactive: draw a box selection or a freehand lasso selection on the frontend, then use the selection geometry in Python to filter your data. The figure is rendered as a static image with an interactive selection overlay: * click and drag for box selection; * hold the `Shift` key and drag for lasso selection. Example `[](#__codelineno-0-1)import matplotlib.pyplot as plt [](#__codelineno-0-2)import marimo as mo [](#__codelineno-0-3)import numpy as np [](#__codelineno-0-4)[](#__codelineno-0-5)x = np.arange(5) [](#__codelineno-0-6)y = x**2 [](#__codelineno-0-7)plt.scatter(x=x, y=y) [](#__codelineno-0-8)ax = mo.ui.matplotlib(plt.gca()) [](#__codelineno-0-9)ax` `[](#__codelineno-1-1)# Filter data using the selection [](#__codelineno-1-2)mask = ax.value.get_mask(x, y) [](#__codelineno-1-3)selected_x, selected_y = x[mask], y[mask]` `[](#__codelineno-2-1)# Check if anything is selected [](#__codelineno-2-2)if ax.value: [](#__codelineno-2-3) print("Data has been selected")` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.matplotlib.value " value property writable (marimo.ui.matplotlib.value)")` | The selected data, with `get_mask(x, y)` returning a mask array corresponding to the selection. **TYPE:** `T` | | PARAMETER | DESCRIPTION | | --- | --- | | `axes` | A matplotlib `Axes` object. The full figure is rendered, but selections map to this axes' coordinate space. **TYPE:** `Axes` | | `debounce` | If `True`, the selection is only sent to Python on mouse-up. If `False` (the default), it streams while dragging. **TYPE:** `bool` **DEFAULT:** `False` | ### axes `property` [¶](#marimo.ui.matplotlib.axes "Permanent link") The associated matplotlib Axes object. ### name `class-attribute` `instance-attribute` [¶](#marimo.ui.matplotlib.name "Permanent link") `[](#__codelineno-0-1)name: Final[str] = 'marimo-matplotlib'` ### text `property` [¶](#marimo.ui.matplotlib.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.matplotlib.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.matplotlib.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.matplotlib.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.matplotlib.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.matplotlib.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.matplotlib.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### left [¶](#marimo.ui.matplotlib.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.matplotlib.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.matplotlib.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Reactive charts with Altair[¶](#reactive-charts-with-altair "Permanent link") ----------------------------------------------------------------------------- ### Disabling automatic selection[¶](#disabling-automatic-selection "Permanent link") marimo automatically adds a default selection based on the mark type, however, you may want to customize the selection behavior of your Altair chart. You can do this by setting `chart_selection` and `legend_selection` to `False`, and using `.add_params` directly on your Altair chart. `[](#__codelineno-1-1)# Create an interval selection [](#__codelineno-1-2)brush = alt.selection_interval(encodings=["x"]) [](#__codelineno-1-3)[](#__codelineno-1-4)_chart = ( [](#__codelineno-1-5) alt.Chart(traces, height=150) [](#__codelineno-1-6) .mark_line() [](#__codelineno-1-7) .encode(x="index:Q", y="value:Q", color="traces:N") [](#__codelineno-1-8) .add_params(brush) # add the selection to the chart [](#__codelineno-1-9)) [](#__codelineno-1-10)[](#__codelineno-1-11)chart = mo.ui.altair_chart( [](#__codelineno-1-12) _chart, [](#__codelineno-1-13) # disable automatic selection [](#__codelineno-1-14) chart_selection=False, [](#__codelineno-1-15) legend_selection=False [](#__codelineno-1-16)) [](#__codelineno-1-17)chart # You can now access chart.value to get the selected data` marimo.ui.altair\_chart [¶](#marimo.ui.altair_chart "Permanent link") --------------------------------------------------------------------- `[](#__codelineno-0-1)altair_chart( [](#__codelineno-0-2) chart: AltairChartType, [](#__codelineno-0-3) chart_selection: Literal["point"] [](#__codelineno-0-4) | Literal["interval"] [](#__codelineno-0-5) | bool = True, [](#__codelineno-0-6) legend_selection: list[str] | bool = True, [](#__codelineno-0-7) *, [](#__codelineno-0-8) label: str = "", [](#__codelineno-0-9) on_change: Callable[[ChartDataType], None] [](#__codelineno-0-10) | None = None, [](#__codelineno-0-11))` Bases: `UIElement[ChartSelection, ChartDataType]` Make reactive charts with Altair. Use `mo.ui.altair_chart` to make Altair charts reactive: select chart data with your cursor on the frontend, get them as a dataframe in Python! Supports polars, pandas, and arrow DataFrames. Examples: `[](#__codelineno-0-1)import altair as alt [](#__codelineno-0-2)import marimo as mo [](#__codelineno-0-3)from vega_datasets import data [](#__codelineno-0-4)[](#__codelineno-0-5)chart = ( [](#__codelineno-0-6) alt.Chart(data.cars()) [](#__codelineno-0-7) .mark_point() [](#__codelineno-0-8) .encode( [](#__codelineno-0-9) x="Horsepower", [](#__codelineno-0-10) y="Miles_per_Gallon", [](#__codelineno-0-11) color="Origin", [](#__codelineno-0-12) ) [](#__codelineno-0-13)) [](#__codelineno-0-14)[](#__codelineno-0-15)chart = mo.ui.altair_chart(chart)` `[](#__codelineno-1-1)# View the chart and selected data as a dataframe [](#__codelineno-1-2)mo.hstack([chart, chart.value])` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.altair_chart.value " value property writable (marimo.ui.altair_chart.value)")` | A dataframe of the plot data filtered by the selections. **TYPE:** `ChartDataType` | | `[dataframe](#marimo.ui.altair_chart.dataframe " dataframe instance-attribute (marimo.ui.altair_chart.dataframe)")` | A dataframe of the unfiltered chart data. **TYPE:** `ChartDataType` | | `[selections](#marimo.ui.altair_chart.selections " selections property (marimo.ui.altair_chart.selections)")` | The selection of the chart; this may be an interval along the name of an axis or a selection of points. **TYPE:** `ChartSelection` | | PARAMETER | DESCRIPTION | | --- | --- | | `chart` | An Altair Chart object. **TYPE:** `Chart` | | `chart_selection` | Selection type, "point", "interval", or a bool. Defaults to True which will automatically detect the best selection type. This is ignored if the chart already has a point/interval selection param. **TYPE:** `Literal['point'] | Literal['interval'] | bool` **DEFAULT:** `True` | | `legend_selection` | List of legend fields (columns) for which to enable selection, True to enable selection for all fields, or False to disable selection entirely. This is ignored if the chart already has a legend selection param. Defaults to True. **TYPE:** `list[str] | bool` **DEFAULT:** `True` | | `label` | Markdown label for the element. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[ChartDataType], None] | None` **DEFAULT:** `None` | ### dataframe `instance-attribute` [¶](#marimo.ui.altair_chart.dataframe "Permanent link") `[](#__codelineno-0-1)dataframe: ChartDataType | None = _get_dataframe_from_chart( [](#__codelineno-0-2) chart [](#__codelineno-0-3))` ### name `class-attribute` `instance-attribute` [¶](#marimo.ui.altair_chart.name "Permanent link") `[](#__codelineno-0-1)name: Final[str] = 'marimo-vega'` ### selections `property` [¶](#marimo.ui.altair_chart.selections "Permanent link") `[](#__codelineno-0-1)selections: ChartSelection` ### text `property` [¶](#marimo.ui.altair_chart.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.altair_chart.value "Permanent link") ### apply\_selection [¶](#marimo.ui.altair_chart.apply_selection "Permanent link") `[](#__codelineno-0-1)apply_selection(df: ChartDataType) -> ChartDataType` Apply the selection to a DataFrame. This method is useful when you have a layered chart and you want to apply the selection to a DataFrame. | PARAMETER | DESCRIPTION | | --- | --- | | `df` | A DataFrame to apply the selection to. **TYPE:** `ChartDataType` | | RETURNS | DESCRIPTION | | --- | --- | | `ChartDataType` | A DataFrame of the plot data filtered by the selections. **TYPE:** `ChartDataType` | Examples: `[](#__codelineno-0-1)import altair as alt [](#__codelineno-0-2)import marimo as mo [](#__codelineno-0-3)from vega_datasets import data [](#__codelineno-0-4)[](#__codelineno-0-5)cars = data.cars() [](#__codelineno-0-6)[](#__codelineno-0-7)_chart = ( [](#__codelineno-0-8) alt.Chart(cars) [](#__codelineno-0-9) .mark_point() [](#__codelineno-0-10) .encode( [](#__codelineno-0-11) x="Horsepower", [](#__codelineno-0-12) y="Miles_per_Gallon", [](#__codelineno-0-13) color="Origin", [](#__codelineno-0-14) ) [](#__codelineno-0-15)) [](#__codelineno-0-16)[](#__codelineno-0-17)chart = mo.ui.altair_chart(_chart) [](#__codelineno-0-18)chart [](#__codelineno-0-19)[](#__codelineno-0-20)# In another cell [](#__codelineno-0-21)selected_df = chart.apply_selection(cars)` ### batch [¶](#marimo.ui.altair_chart.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.altair_chart.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.altair_chart.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.altair_chart.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.altair_chart.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### left [¶](#marimo.ui.altair_chart.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.altair_chart.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.altair_chart.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | ### Performance and Data Transformers[¶](#performance-and-data-transformers "Permanent link") Altair has a concept of [data](https://altair-viz.github.io/user_guide/data_transformers.html) transformers, which can be used to improve performance. Some examples are: * pandas Dataframe has to be sanitized and serialized to JSON; * the rows of a Dataframe might need to be sampled or limited to a maximum number; * the Dataframe might be written to a `.csv` or `.json` file for performance reasons. By default, Altair uses the `default` data transformer, which is the slowest in marimo. It is limited to 5000 rows (although we increase this to `20_000` rows as marimo can handle this). This includes the data inside the HTML that is being sent over the network, which can also be limited by marimo's maximum message size. It is recommended to use the `marimo_csv` data transformer, which is the most performant and can handle the largest datasets: it converts the data to a CSV file which is smaller and can be sent over the network. This can handle up to +400,000 rows with no issues. When using `mo.ui.altair_chart`, we automatically set the data transformer to `marimo_csv` for you. If you are using Altair directly, you can set the data transformer using the following code: `[](#__codelineno-2-1)import altair as alt [](#__codelineno-2-2)alt.data_transformers.enable('marimo_csv')` Reactive plots with Plotly[¶](#reactive-plots-with-plotly "Permanent link") --------------------------------------------------------------------------- Supported charts marimo can render any Plotly plot, but [`mo.ui.plotly`](#marimo.ui.plotly " marimo.ui.plotly") only supports reactive selections for scatter/scattergl plots, pure line charts, bar charts, histograms, heatmaps, treemaps, and sunburst charts. If you require other kinds of selection, please [file an issue](https://github.com/marimo-team/marimo/issues). marimo.ui.plotly [¶](#marimo.ui.plotly "Permanent link") -------------------------------------------------------- `[](#__codelineno-0-1)plotly( [](#__codelineno-0-2) figure: Figure, [](#__codelineno-0-3) config: dict[str, Any] | None = None, [](#__codelineno-0-4) renderer_name: str | None = None, [](#__codelineno-0-5) *, [](#__codelineno-0-6) label: str = "", [](#__codelineno-0-7) on_change: Callable[[JSONType], None] | None = None, [](#__codelineno-0-8))` Bases: `UIElement[PlotlySelection, list[dict[str, Any]]]` Make reactive plots with Plotly. Use `mo.ui.plotly` to make plotly plots reactive: select data with your cursor on the frontend, get them as a list of dicts in Python! This function supports scatter plots, scattergl plots, line charts, area charts, bar charts, histograms, treemap charts, sunburst charts, and heatmaps. Examples: `[](#__codelineno-0-1)import plotly.express as px [](#__codelineno-0-2)import marimo as mo [](#__codelineno-0-3)from vega_datasets import data [](#__codelineno-0-4)[](#__codelineno-0-5)_plot = px.scatter( [](#__codelineno-0-6) data.cars(), x="Horsepower", y="Miles_per_Gallon", color="Origin" [](#__codelineno-0-7)) [](#__codelineno-0-8)[](#__codelineno-0-9)plot = mo.ui.plotly(_plot)` `[](#__codelineno-1-1)# View the plot and selected data [](#__codelineno-1-2)mo.hstack([plot, plot.value])` Or with custom configuration: `[](#__codelineno-2-1)plot = mo.ui.plotly( [](#__codelineno-2-2) _plot, [](#__codelineno-2-3) config={"staticPlot": True}, [](#__codelineno-2-4))` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.plotly.value " value property writable (marimo.ui.plotly.value)")` | A dict of the plot data. **TYPE:** `Dict[str, Any]` | | `[ranges](#marimo.ui.plotly.ranges " ranges property (marimo.ui.plotly.ranges)")` | The selection of the plot; this may be an interval along the name of an axis. **TYPE:** `Dict[str, List[float]]` | | `[points](#marimo.ui.plotly.points " points property (marimo.ui.plotly.points)")` | The selected points data. **TYPE:** `List[Dict[str, Any]]` | | `[indices](#marimo.ui.plotly.indices " indices property (marimo.ui.plotly.indices)")` | The indices of selected points. **TYPE:** `List[int]` | | PARAMETER | DESCRIPTION | | --- | --- | | `figure` | A plotly Figure object. **TYPE:** `Figure` | | `config` | Configuration for the plot. This is a dictionary that is passed directly to plotly. See the plotly documentation for more information: [https://plotly.com/javascript/configuration-options/](https://plotly.com/javascript/configuration-options/) This takes precedence over the default configuration of the renderer. Defaults to None. **TYPE:** `Dict[str, Any] | None` **DEFAULT:** `None` | | `renderer_name` | Renderer to use for the plot. If this is not provided, the default renderer (`pio.renderers.default`) is used. Defaults to None. **TYPE:** `str | None` **DEFAULT:** `None` | | `label` | Markdown label for the element. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | `on_change` | Callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[JSONType], None] | None` **DEFAULT:** `None` | ### indices `property` [¶](#marimo.ui.plotly.indices "Permanent link") Get the indices of selected points in the plot. | RETURNS | DESCRIPTION | | --- | --- | | `list[int]` | List\[int\]: A list of indices corresponding to the selected points. Returns an empty list if no points are selected. | ### name `class-attribute` `instance-attribute` [¶](#marimo.ui.plotly.name "Permanent link") `[](#__codelineno-0-1)name: Final[str] = 'marimo-plotly'` ### points `property` [¶](#marimo.ui.plotly.points "Permanent link") `[](#__codelineno-0-1)points: list[dict[str, Any]]` Get the selected points data from the plot. | RETURNS | DESCRIPTION | | --- | --- | | `list[dict[str, Any]]` | List\[Dict\[str, Any\]\]: A list of dictionaries containing the data for each selected point. Returns an empty list if no points are selected. | ### ranges `property` [¶](#marimo.ui.plotly.ranges "Permanent link") `[](#__codelineno-0-1)ranges: dict[str, list[float]]` Get the range selection of the plot. | RETURNS | DESCRIPTION | | --- | --- | | `dict[str, list[float]]` | Dict\[str, List\[float\]\]: A dictionary mapping field names to their selected ranges, where each range is a list of \[min, max\] values. Returns an empty dict if no range selection exists. | ### text `property` [¶](#marimo.ui.plotly.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.plotly.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.plotly.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.plotly.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.plotly.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.plotly.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.plotly.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### left [¶](#marimo.ui.plotly.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.plotly.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.plotly.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Interactive matplotlib[¶](#interactive-matplotlib "Permanent link") ------------------------------------------------------------------- marimo.mpl.interactive [¶](#marimo.mpl.interactive "Permanent link") -------------------------------------------------------------------- `[](#__codelineno-0-1)interactive(figure: Figure | SubFigure | Axes) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Render a matplotlib figure using an interactive viewer. The interactive viewer allows you to pan, zoom, and see plot coordinates on mouse hover. Example `[](#__codelineno-0-1)plt.plot([1, 2]) [](#__codelineno-0-2)# plt.gcf() gets the current figure [](#__codelineno-0-3)mo.mpl.interactive(plt.gcf())` | PARAMETER | DESCRIPTION | | --- | --- | | `figure` | A matplotlib `Figure` or `Axes` object. **TYPE:** `matplotlib Figure or Axes` | | RETURNS | DESCRIPTION | | --- | --- | | `Html` | An interactive matplotlib figure as an `Html` object. **TYPE:** `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | Source code in `marimo/_plugins/stateless/mpl/_mpl.py`
@mddoc
def interactive(figure: Union[Figure, SubFigure, Axes]) -> Html:
    """Render a matplotlib figure using an interactive viewer.

    The interactive viewer allows you to pan, zoom, and see plot coordinates
    on mouse hover.

    Example:
        ```python
        plt.plot([1, 2])
        # plt.gcf() gets the current figure
        mo.mpl.interactive(plt.gcf())
        ```

    Args:
        figure (matplotlib Figure or Axes): A matplotlib `Figure` or `Axes` object.

    Returns:
        Html: An interactive matplotlib figure as an `Html` object.
    """
    # No top-level imports of matplotlib, since it isn't a required
    # dependency
    from matplotlib.axes import Axes

    if isinstance(figure, Axes):
        maybe_figure = figure.get_figure()
        assert maybe_figure is not None, "Axes object does not have a Figure"
        figure = maybe_figure

    ctx = get_context()
    if not isinstance(ctx, KernelRuntimeContext):
        return NonInteractiveMplHtml(figure)

    # When virtual files are not supported (e.g., during HTML export),
    # fall back to static PNG instead of interactive plot
    if not ctx.virtual_files_supported:
        return NonInteractiveMplHtml(figure)

    from marimo._plugins.ui._impl.from_mpl_interactive import mpl_interactive

    return mpl_interactive(figure)
Leafmap[¶](#leafmap "Permanent link") ------------------------------------- marimo supports rendering [Leafmap](https://leafmap.org/) maps using the `folium` and `plotly` backends. Other plotting libraries[¶](#other-plotting-libraries "Permanent link") ----------------------------------------------------------------------- You can use all the popular plotting libraries with marimo, such as: * [Matplotlib](https://matplotlib.org/) * [Plotly](https://plotly.com/) * [Seaborn](https://seaborn.pydata.org/) * [Bokeh](https://bokeh.org/) * [Altair](https://altair-viz.github.io/) * [HoloViews](http://holoviews.org/) * [hvPlot](https://hvplot.holoviz.org/) * [Leafmap](https://leafmap.org/) * [Pygwalker](https://kanaries.net/pygwalker)
Download - marimo https://docs.marimo.io/api/media/download/ Tip: paste this code into an empty cell, and the marimo editor will create cells for you `# /// script # requires-python = ">=3.12" # dependencies = [ # "marimo", # "pandas==2.2.3", # ] # /// import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo return (mo,) @app.cell(hide_code=True) def _(json, mo, pd): # Text file download text_download = mo.download( data="Hello, world!".encode("utf-8"), filename="hello.txt", mimetype="text/plain", label="Download text", ) # CSV download using pandas df = pd.DataFrame({"name": ["Alice", "Bob", "Charlie"], "age": [25, 30, 35]}) csv_download = mo.download( data=df.to_csv().encode("utf-8"), filename="data.csv", mimetype="text/csv", label="Download CSV", ) # JSON download data = {"message": "Hello", "count": 42} json_download = mo.download( data=json.dumps(data).encode("utf-8"), filename="data.json", mimetype="application/json", label="Download JSON", ) mo.hstack([text_download, csv_download, json_download]) return @app.cell(hide_code=True) def _(json, mo, pd): import time import asyncio # Text file download with lazy loading def get_text_data(): time.sleep(1) return "Hello, world!".encode("utf-8") text_download_lazy = mo.download( data=get_text_data, filename="hello.txt", mimetype="text/plain", label="Download text", ) # CSV download using pandas with lazy loading async def get_csv_data(): await asyncio.sleep(1) _df = pd.DataFrame( {"name": ["Alice", "Bob", "Charlie"], "age": [25, 30, 35]} ) return _df csv_download_lazy = mo.download( data=get_csv_data, filename="data.csv", mimetype="text/csv", label="Download CSV", ) # JSON download with lazy loading async def get_json_data(): await asyncio.sleep(1) _data = {"message": "Hello", "count": 42} return json.dumps(_data).encode("utf-8") json_download_lazy = mo.download( data=get_json_data, filename="data.json", mimetype="application/json", label="Download JSON", ) mo.hstack([text_download_lazy, csv_download_lazy, json_download_lazy]) return @app.cell def _(): import pandas as pd import json return json, pd if __name__ == "__main__": app.run()` Image - marimo https://docs.marimo.io/api/media/image/ marimo.image [¶](#marimo.image "Permanent link") ------------------------------------------------ `[](#__codelineno-0-1)image( [](#__codelineno-0-2) src: ImageLike, [](#__codelineno-0-3) alt: str | None = None, [](#__codelineno-0-4) width: int | str | None = None, [](#__codelineno-0-5) height: int | str | None = None, [](#__codelineno-0-6) rounded: bool = False, [](#__codelineno-0-7) style: dict[str, Any] | None = None, [](#__codelineno-0-8) caption: str | None = None, [](#__codelineno-0-9) vmin: float | None = None, [](#__codelineno-0-10) vmax: float | None = None, [](#__codelineno-0-11)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Render an image as HTML. Examples: `[](#__codelineno-0-1)# Render an image from a local file [](#__codelineno-0-2)mo.image(src="path/to/image.png")` `[](#__codelineno-1-1)# Render an image from a URL [](#__codelineno-1-2)mo.image( [](#__codelineno-1-3) src="https://marimo.io/logo.png", [](#__codelineno-1-4) alt="Marimo logo", [](#__codelineno-1-5) width=100, [](#__codelineno-1-6) height=100, [](#__codelineno-1-7) rounded=True, [](#__codelineno-1-8) caption="Marimo logo", [](#__codelineno-1-9))` `[](#__codelineno-2-1)# Compare images with consistent intensity scaling [](#__codelineno-2-2)import numpy as np [](#__codelineno-2-3)[](#__codelineno-2-4)dark = np.full((100, 100), 50) [](#__codelineno-2-5)light = np.full((100, 100), 200) [](#__codelineno-2-6)mo.hstack( [](#__codelineno-2-7) [ [](#__codelineno-2-8) mo.image(dark, vmin=0, vmax=255), [](#__codelineno-2-9) mo.image(light, vmin=0, vmax=255), [](#__codelineno-2-10) ] [](#__codelineno-2-11))` | PARAMETER | DESCRIPTION | | --- | --- | | `src` | a path or URL to an image, a file-like object (opened in binary mode), or array-like object. When `src` is array-like, `uint8` arrays are used as-is. Other dtypes are min-max normalized unless `vmin`/`vmax` are provided. **TYPE:** `ImageLike` | | `alt` | the alt text of the image **TYPE:** `str | None` **DEFAULT:** `None` | | `width` | the width of the image in pixels or a string with units **TYPE:** `int | str | None` **DEFAULT:** `None` | | `height` | the height of the image in pixels or a string with units **TYPE:** `int | str | None` **DEFAULT:** `None` | | `rounded` | whether to round the corners of the image **TYPE:** `bool` **DEFAULT:** `False` | | `style` | a dictionary of CSS styles to apply to the image **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `caption` | the caption of the image **TYPE:** `str | None` **DEFAULT:** `None` | | `vmin` | minimum value for normalization when `src` is an array. Values below `vmin` are clipped. If `None`, defaults to the array minimum. Only used when `src` is array-like. **TYPE:** `float | None` **DEFAULT:** `None` | | `vmax` | maximum value for normalization when `src` is an array. Values above `vmax` are clipped. If `None`, defaults to the array maximum. Only used when `src` is array-like. **TYPE:** `float | None` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | `Html` object | Image Compare - marimo https://docs.marimo.io/api/media/image_compare/ marimo.image\_compare [¶](#marimo.image_compare "Permanent link") ----------------------------------------------------------------- `[](#__codelineno-0-1)image_compare( [](#__codelineno-0-2) before_image: ImageLike, [](#__codelineno-0-3) after_image: ImageLike, [](#__codelineno-0-4) value: float = 50, [](#__codelineno-0-5) direction: Literal[ [](#__codelineno-0-6) "horizontal", "vertical" [](#__codelineno-0-7) ] = "horizontal", [](#__codelineno-0-8) width: int | str | None = None, [](#__codelineno-0-9) height: int | str | None = None, [](#__codelineno-0-10)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Render an image comparison slider to compare two images side by side. Examples: `[](#__codelineno-0-1)# Basic usage with two images [](#__codelineno-0-2)mo.image_compare(before_image="before.jpg", after_image="after.jpg")` `[](#__codelineno-1-1)# With custom settings [](#__codelineno-1-2)mo.image_compare( [](#__codelineno-1-3) before_image="original.png", [](#__codelineno-1-4) after_image="processed.png", [](#__codelineno-1-5) value=30, # Initial slider position at 30% [](#__codelineno-1-6) direction="vertical", [](#__codelineno-1-7) width=500, [](#__codelineno-1-8) height=400, [](#__codelineno-1-9))` | PARAMETER | DESCRIPTION | | --- | --- | | `before_image` | The "before" image to show in the comparison slider. Can be a path, URL, or array-like object. **TYPE:** `ImageLike` | | `after_image` | The "after" image to show in the comparison slider. Can be a path, URL, or array-like object. **TYPE:** `ImageLike` | | `value` | Initial position of the slider (0-100), defaults to 50. **TYPE:** `float` **DEFAULT:** `50` | | `direction` | Orientation of the slider, either "horizontal" or "vertical". Defaults to "horizontal". **TYPE:** `Literal['horizontal', 'vertical']` **DEFAULT:** `'horizontal'` | | `width` | Width of the component in pixels or CSS units. **TYPE:** `int | str | None` **DEFAULT:** `None` | | `height` | Height of the component in pixels or CSS units. **TYPE:** `int | str | None` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | `Html` object with the image comparison slider. | PDF - marimo https://docs.marimo.io/api/media/pdf/ marimo.pdf [¶](#marimo.pdf "Permanent link") -------------------------------------------- `[](#__codelineno-0-1)pdf( [](#__codelineno-0-2) src: Path | str | IOBase, [](#__codelineno-0-3) initial_page: int | None = None, [](#__codelineno-0-4) width: int | str | None = "100%", [](#__codelineno-0-5) height: int | str | None = "70vh", [](#__codelineno-0-6) style: dict[str, Any] | None = None, [](#__codelineno-0-7)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Render a PDF. This currently uses the native browser PDF viewer, but may be replaced with a custom viewer. Example `[](#__codelineno-0-1)# from a URL [](#__codelineno-0-2)mo.pdf( [](#__codelineno-0-3) src="https://arxiv.org/pdf/2104.00282.pdf", [](#__codelineno-0-4) width="100%", [](#__codelineno-0-5) height="50vh", [](#__codelineno-0-6)) [](#__codelineno-0-7)[](#__codelineno-0-8)# from a local file [](#__codelineno-0-9)from pathlib import Path [](#__codelineno-0-10)[](#__codelineno-0-11)mo.pdf(src=Path("paper.pdf"))` | PARAMETER | DESCRIPTION | | --- | --- | | `src` | the URL of the pdf, a file-like object, or a pathlib.Path object **TYPE:** `Path | str | IOBase` | | `initial_page` | the page to open the pdf to. only works if `src` is a URL **TYPE:** `int | None` **DEFAULT:** `None` | | `width` | the width of the pdf **TYPE:** `int | str | None` **DEFAULT:** `'100%'` | | `height` | the height of the pdf. for a percentage of the user's viewport, use a string like `"50vh"` **TYPE:** `int | str | None` **DEFAULT:** `'70vh'` | | `style` | a dictionary of CSS styles to apply to the pdf **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | `Html` object | Plain Text - marimo https://docs.marimo.io/api/media/plain_text/ marimo.plain\_text [¶](#marimo.plain_text "Permanent link") ----------------------------------------------------------- `[](#__codelineno-0-1)plain_text(text: str) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Text that's fixed-width, with spaces and newlines preserved. | PARAMETER | DESCRIPTION | | --- | --- | | `text` | text to output **TYPE:** `str` | | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object representing the text. | Outputs - marimo https://docs.marimo.io/api/outputs/ Cell outputs[¶](#cell-outputs "Permanent link") ----------------------------------------------- Cell outputs Every cell in a marimo notebook can have a visual **output**. When editing, outputs are displayed above cells. When running a notebook as an app, its UI is an arrangement of outputs. A cell's output is by default its last expression. You can also create outputs programmatically, using `mo.output.replace()` and `mo.output.append()`. marimo.output.replace [¶](#marimo.output.replace "Permanent link") ------------------------------------------------------------------ `[](#__codelineno-0-1)replace(value: object) -> None` Replace a cell's output with a new one. Call `mo.output.replace()` to write to a cell's output area, replacing the existing output, if any. | PARAMETER | DESCRIPTION | | --- | --- | | `value` | object to output **TYPE:** `object` | **Watch `mo.output.replace` in action** See a demo of how `mo.output.replace` works in this [short YouTube video](https://youtube.com/shorts/tCMeQb-PqNU?si=7PeFzQJzNvXsLoXN). marimo.output.append [¶](#marimo.output.append "Permanent link") ---------------------------------------------------------------- `[](#__codelineno-0-1)append(value: object) -> None` Append a new object to a cell's output. Call this function to incrementally build a cell's output. Appended outputs are stacked vertically. | PARAMETER | DESCRIPTION | | --- | --- | | `value` | object to output **TYPE:** `object` | marimo.output.clear [¶](#marimo.output.clear "Permanent link") -------------------------------------------------------------- Clear a cell's output. marimo.output.replace\_at\_index [¶](#marimo.output.replace_at_index "Permanent link") -------------------------------------------------------------------------------------- `[](#__codelineno-0-1)replace_at_index(value: object, idx: int) -> None` Replace a cell's output at the given index with value. Call this function to replace an existing object in a cell's output. If idx is equal to the length of the output, this is equivalent to an append. | PARAMETER | DESCRIPTION | | --- | --- | | `value` | new object to replace an existing object **TYPE:** `object` | | `idx` | index of output to replace **TYPE:** `int` | Last expression replaces existing output Ending a cell with a non-`None` expression is the same as calling `mo.output.replace()` on it: the last expression replaces any output you may have already written. Wrap the last expression in `mo.output.append` if you want to add to an existing output instead of replacing it. ### Display cell code in marimo's app views[¶](#display-cell-code-in-marimos-app-views "Permanent link") Use `mo.show_code()` to display the cell's code in the output area, which will then be visible in all app views. marimo.show\_code [¶](#marimo.show_code "Permanent link") --------------------------------------------------------- `[](#__codelineno-0-1)show_code( [](#__codelineno-0-2) output: object = None, [](#__codelineno-0-3) *, [](#__codelineno-0-4) position: Literal["above", "below"] = "below", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Display an output along with the code of the current cell. Use `mo.show_code` to show the code of the current cell along with the cell's output. This is useful if you want a cell's code to appear in the app preview or when running the notebook as an app with `marimo run`. In the displayed code, all occurrences of mo.show\_code(...) will be replaced with ... Show code that produces the output `factorial(5)`: `[](#__codelineno-0-1)def factorial(n: int) -> int: [](#__codelineno-0-2) if n == 0: [](#__codelineno-0-3) return 1 [](#__codelineno-0-4) return n * factorial(n - 1) [](#__codelineno-0-5) [](#__codelineno-0-6)[](#__codelineno-0-7)mo.show_code(factorial(5))` Show code of a cell, without an output: `[](#__codelineno-1-1)def factorial(n: int) -> int: [](#__codelineno-1-2) if n == 0: [](#__codelineno-1-3) return 1 [](#__codelineno-1-4) return n * factorial(n - 1) [](#__codelineno-1-5) [](#__codelineno-1-6)[](#__codelineno-1-7)mo.show_code()` | PARAMETER | DESCRIPTION | | --- | --- | | `output` | the output to display with the cell's code; omit the output to just show the cell's code. **TYPE:** `object` **DEFAULT:** `None` | | `position` | Where to display the code relative to the output. Use "above" to show code above the output, or "below" (default) to show code below the output. **TYPE:** `Literal['above', 'below']` **DEFAULT:** `'below'` | | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | HTML of the `output` arg displayed with its code. | Console outputs[¶](#console-outputs "Permanent link") ----------------------------------------------------- Console outputs Text written to `stdout`/`stderr`, including print statements and logs, shows up in a console output area below a cell. By default, these console outputs don't appear when running a marimo notebook as an app. If you do want them to appear in apps, marimo provides utility functions for capturing console outputs and redirecting them to cell outputs. marimo.redirect\_stdout [¶](#marimo.redirect_stdout "Permanent link") --------------------------------------------------------------------- `[](#__codelineno-0-1)redirect_stdout() -> Iterator[None]` Redirect stdout to a cell's output area. Examples: `[](#__codelineno-0-1)with mo.redirect_stdout(): [](#__codelineno-0-2) # These print statements will show up in the cell's output area [](#__codelineno-0-3) print("Hello!") [](#__codelineno-0-4) print("World!")` marimo.redirect\_stderr [¶](#marimo.redirect_stderr "Permanent link") --------------------------------------------------------------------- `[](#__codelineno-0-1)redirect_stderr() -> Iterator[None]` Redirect `stderr` to a cell's output area. Examples: `[](#__codelineno-0-1)with mo.redirect_stderr(): [](#__codelineno-0-2) # These messages will show up in the cell's output area [](#__codelineno-0-3) sys.stderr.write("Hello!") [](#__codelineno-0-4) sys.stderr.write("World!")` marimo.capture\_stdout [¶](#marimo.capture_stdout "Permanent link") ------------------------------------------------------------------- `[](#__codelineno-0-1)capture_stdout() -> Iterator[StringIO]` Capture standard output. Use this context manager to capture print statements and other output sent to standard output. Examples: `[](#__codelineno-0-1)with mo.capture_stdout() as buffer: [](#__codelineno-0-2) print("Hello!") [](#__codelineno-0-3)output = buffer.getvalue()` marimo.capture\_stderr [¶](#marimo.capture_stderr "Permanent link") ------------------------------------------------------------------- `[](#__codelineno-0-1)capture_stderr() -> Iterator[StringIO]` Capture standard error. Use this context manager to capture output sent to standard error. Examples: `[](#__codelineno-0-1)with mo.capture_stderr() as buffer: [](#__codelineno-0-2) sys.stderr.write("Hello!") [](#__codelineno-0-3)output = buffer.getvalue()` Object inspection[¶](#object-inspection "Permanent link") --------------------------------------------------------- Use [`mo.inspect`](https://docs.marimo.io/api/miscellaneous/#marimo.inspect " marimo.inspect") to create a rich display of Python objects for exploring their attributes, methods, and documentation. Video - marimo https://docs.marimo.io/api/media/video/ marimo.video [¶](#marimo.video "Permanent link") ------------------------------------------------ `[](#__codelineno-0-1)video( [](#__codelineno-0-2) src: str | bytes | BytesIO | BufferedReader, [](#__codelineno-0-3) controls: bool = True, [](#__codelineno-0-4) muted: bool = False, [](#__codelineno-0-5) autoplay: bool = False, [](#__codelineno-0-6) loop: bool = False, [](#__codelineno-0-7) width: int | str | None = None, [](#__codelineno-0-8) height: int | str | None = None, [](#__codelineno-0-9) rounded: bool = False, [](#__codelineno-0-10)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Render an video as HTML. Example `[](#__codelineno-0-1)mo.video( [](#__codelineno-0-2) src="https://v3.cdnpk.net/videvo_files/video/free/2013-08/large_watermarked/hd0992_preview.mp4", [](#__codelineno-0-3) controls=False, [](#__codelineno-0-4))` | PARAMETER | DESCRIPTION | | --- | --- | | `src` | the URL of the video or a file-like object **TYPE:** `str | bytes | BytesIO | BufferedReader` | | `controls` | whether to show the controls **TYPE:** `bool` **DEFAULT:** `True` | | `muted` | whether to mute the video **TYPE:** `bool` **DEFAULT:** `False` | | `autoplay` | whether to autoplay the video. the video will only autoplay if `muted` is `True` **TYPE:** `bool` **DEFAULT:** `False` | | `loop` | whether to loop the video **TYPE:** `bool` **DEFAULT:** `False` | | `width` | the width of the video in pixels or a string with units **TYPE:** `int | str | None` **DEFAULT:** `None` | | `height` | the height of the video in pixels or a string with units **TYPE:** `int | str | None` **DEFAULT:** `None` | | `rounded` | whether to round the corners of the video **TYPE:** `bool` **DEFAULT:** `False` | | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | `Html` object | Progress Bars and Status - marimo https://docs.marimo.io/api/status/ Use progress bars or spinners to visualize loading status in your notebooks and apps. Useful when iterating over collections or loading data from files, databases, or APIs. Progress bar[¶](#progress-bar "Permanent link") ----------------------------------------------- You can display a progress bar while iterating over a collection, similar to `tqdm`. Source code for `examples/outputs/progress_bar.py` Tip: paste this code into an empty cell, and the marimo editor will create cells for you `import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo import asyncio return asyncio, mo @app.cell def _(mo): rerun = mo.ui.button(label="Rerun") rerun return (rerun,) @app.cell async def _(asyncio, mo, rerun): rerun for _ in mo.status.progress_bar( range(10), title="Loading", subtitle="Please wait", show_eta=True, show_rate=True, ): await asyncio.sleep(0.5) return @app.cell def _(mo): rerun_slow = mo.ui.button(label="Rerun Slow") rerun_slow return (rerun_slow,) @app.cell async def _(asyncio, mo, rerun_slow): rerun_slow for _ in mo.status.progress_bar( range(2), title="Loading", subtitle="Please wait", show_eta=True, show_rate=True ): await asyncio.sleep(12) return if __name__ == "__main__": app.run()` marimo.status.progress\_bar [¶](#marimo.status.progress_bar "Permanent link") ----------------------------------------------------------------------------- `[](#__codelineno-0-1)progress_bar( [](#__codelineno-0-2) collection: Collection[S] = ..., [](#__codelineno-0-3) *, [](#__codelineno-0-4) title: str | None = ..., [](#__codelineno-0-5) subtitle: str | None = ..., [](#__codelineno-0-6) completion_title: str | None = ..., [](#__codelineno-0-7) completion_subtitle: str | None = ..., [](#__codelineno-0-8) total: int | None = ..., [](#__codelineno-0-9) show_rate: bool = ..., [](#__codelineno-0-10) show_eta: bool = ..., [](#__codelineno-0-11) remove_on_exit: bool = ..., [](#__codelineno-0-12) disabled: bool = ..., [](#__codelineno-0-13))` `[](#__codelineno-0-1)progress_bar( [](#__codelineno-0-2) collection: Iterator[S] | AsyncIterable[S] = ..., [](#__codelineno-0-3) *, [](#__codelineno-0-4) title: str | None = ..., [](#__codelineno-0-5) subtitle: str | None = ..., [](#__codelineno-0-6) completion_title: str | None = ..., [](#__codelineno-0-7) completion_subtitle: str | None = ..., [](#__codelineno-0-8) total: int = ..., [](#__codelineno-0-9) show_rate: bool = ..., [](#__codelineno-0-10) show_eta: bool = ..., [](#__codelineno-0-11) remove_on_exit: bool = ..., [](#__codelineno-0-12) disabled: bool = ..., [](#__codelineno-0-13))` `[](#__codelineno-0-1)progress_bar( [](#__codelineno-0-2) collection: None = ..., [](#__codelineno-0-3) *, [](#__codelineno-0-4) title: str | None = ..., [](#__codelineno-0-5) subtitle: str | None = ..., [](#__codelineno-0-6) completion_title: str | None = ..., [](#__codelineno-0-7) completion_subtitle: str | None = ..., [](#__codelineno-0-8) total: int = ..., [](#__codelineno-0-9) show_rate: bool = ..., [](#__codelineno-0-10) show_eta: bool = ..., [](#__codelineno-0-11) remove_on_exit: bool = ..., [](#__codelineno-0-12) disabled: bool = ..., [](#__codelineno-0-13))` `[](#__codelineno-0-1)progress_bar( [](#__codelineno-0-2) collection: Collection[S] [](#__codelineno-0-3) | Iterator[S] [](#__codelineno-0-4) | AsyncIterable[S] [](#__codelineno-0-5) | None = None, [](#__codelineno-0-6) *, [](#__codelineno-0-7) title: str | None = None, [](#__codelineno-0-8) subtitle: str | None = None, [](#__codelineno-0-9) completion_title: str | None = None, [](#__codelineno-0-10) completion_subtitle: str | None = None, [](#__codelineno-0-11) total: int | None = None, [](#__codelineno-0-12) show_rate: bool = True, [](#__codelineno-0-13) show_eta: bool = True, [](#__codelineno-0-14) remove_on_exit: bool = False, [](#__codelineno-0-15) disabled: bool = False, [](#__codelineno-0-16))` Bases: `Generic[S]` Iterate over a collection and show a progress bar. Examples: `[](#__codelineno-0-1)for i in mo.status.progress_bar(range(10)): [](#__codelineno-0-2) ...` You can optionally provide a title and subtitle to show during iteration, and a title/subtitle to show upon completion: `[](#__codelineno-1-1)with mo.status.progress_bar(total=10) as bar: [](#__codelineno-1-2) for i in range(10): [](#__codelineno-1-3) ... [](#__codelineno-1-4) bar.update()` The `update` method accepts the optional keyword arguments `increment` (defaults to `1`), `title`, and `subtitle`. For performance reasons, the progress bar is only updated in the UI every 150ms. | PARAMETER | DESCRIPTION | | --- | --- | | `collection` | Optional collection to iterate over. **TYPE:** `Union[Collection[S], Iterator[S], AsyncIterable[S]]` **DEFAULT:** `None` | | `title` | Optional title. **TYPE:** `str` **DEFAULT:** `None` | | `subtitle` | Optional subtitle. **TYPE:** `str` **DEFAULT:** `None` | | `completion_title` | Optional title to show during completion. **TYPE:** `str` **DEFAULT:** `None` | | `completion_subtitle` | Optional subtitle to show during completion. **TYPE:** `str` **DEFAULT:** `None` | | `total` | Optional total number of items to iterate over. **TYPE:** `int` **DEFAULT:** `None` | | `show_rate` | If True, show the rate of progress (items per second or duration per iteration). **TYPE:** `bool` **DEFAULT:** `True` | | `show_eta` | If True, show the estimated time of completion. **TYPE:** `bool` **DEFAULT:** `True` | | `remove_on_exit` | If True, remove the progress bar from output on exit. **TYPE:** `bool` **DEFAULT:** `False` | | `disabled` | If True, disable the progress bar. **TYPE:** `bool` **DEFAULT:** `False` | ### collection `instance-attribute` [¶](#marimo.status.progress_bar.collection "Permanent link") ### completion\_subtitle `instance-attribute` [¶](#marimo.status.progress_bar.completion_subtitle "Permanent link") `[](#__codelineno-0-1)completion_subtitle = completion_subtitle` ### completion\_title `instance-attribute` [¶](#marimo.status.progress_bar.completion_title "Permanent link") `[](#__codelineno-0-1)completion_title = completion_title` ### disabled `instance-attribute` [¶](#marimo.status.progress_bar.disabled "Permanent link") ### progress `instance-attribute` [¶](#marimo.status.progress_bar.progress "Permanent link") `[](#__codelineno-0-1)progress = ProgressBar( [](#__codelineno-0-2) title=title, [](#__codelineno-0-3) subtitle=subtitle, [](#__codelineno-0-4) total=total, [](#__codelineno-0-5) show_rate=show_rate, [](#__codelineno-0-6) show_eta=show_eta, [](#__codelineno-0-7))` ### remove\_on\_exit `instance-attribute` [¶](#marimo.status.progress_bar.remove_on_exit "Permanent link") `[](#__codelineno-0-1)remove_on_exit = remove_on_exit` ### step `instance-attribute` [¶](#marimo.status.progress_bar.step "Permanent link") Spinner[¶](#spinner "Permanent link") ------------------------------------- Source code for `examples/outputs/spinner.py` Tip: paste this code into an empty cell, and the marimo editor will create cells for you `import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(mo): rerun = mo.ui.button(label="Rerun") rerun return (rerun,) @app.cell async def _(mo, rerun): import asyncio rerun with mo.status.spinner(title="Loading...") as _spinner: await asyncio.sleep(1) _spinner.update("Almost done") await asyncio.sleep(1) _spinner.update("Done") return if __name__ == "__main__": app.run()` marimo.status.spinner [¶](#marimo.status.spinner "Permanent link") ------------------------------------------------------------------ `[](#__codelineno-0-1)spinner( [](#__codelineno-0-2) title: str | None = None, [](#__codelineno-0-3) subtitle: str | None = None, [](#__codelineno-0-4) remove_on_exit: bool = True, [](#__codelineno-0-5))` Show a loading spinner. Use `mo.status.spinner()` as a context manager to show a loading spinner. You can optionally pass a title and subtitle. Examples: `[](#__codelineno-0-1)with mo.status.spinner(subtitle="Loading data ...") as _spinner: [](#__codelineno-0-2) data = expensive_function() [](#__codelineno-0-3) _spinner.update(subtitle="Crunching numbers ...") [](#__codelineno-0-4) ... [](#__codelineno-0-5)[](#__codelineno-0-6)mo.ui.table(data)` You can also show the spinner without a context manager: `[](#__codelineno-1-1)mo.status.spinner(title="Loading ...") if condition else mo.md("Done!")` | PARAMETER | DESCRIPTION | | --- | --- | | `title` | Optional title. **TYPE:** `str` **DEFAULT:** `None` | | `subtitle` | Optional subtitle. **TYPE:** `str` **DEFAULT:** `None` | | `remove_on_exit` | If True, the spinner is removed from output on exit. Defaults to True. **TYPE:** `bool` **DEFAULT:** `True` | ### remove\_on\_exit `instance-attribute` [¶](#marimo.status.spinner.remove_on_exit "Permanent link") `[](#__codelineno-0-1)remove_on_exit = remove_on_exit` ### spinner `instance-attribute` [¶](#marimo.status.spinner.spinner "Permanent link") `[](#__codelineno-0-1)spinner = Spinner(title=title, subtitle=subtitle)` ### subtitle `instance-attribute` [¶](#marimo.status.spinner.subtitle "Permanent link") ### title `instance-attribute` [¶](#marimo.status.spinner.title "Permanent link") HTML - marimo https://docs.marimo.io/api/html/ All marimo elements extend the HTML element class. marimo.as\_html [¶](#marimo.as_html "Permanent link") ----------------------------------------------------- `[](#__codelineno-0-1)as_html(value: object) -> [Html](#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Convert a value to HTML that can be embedded into markdown. This function returns an `Html` object representing `value`. Use it to embed values into Markdown or other HTML strings. | PARAMETER | DESCRIPTION | | --- | --- | | `value` | An object **TYPE:** `object` | | RETURNS | DESCRIPTION | | --- | --- | | `[Html](#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object | Example `[](#__codelineno-0-1)import matplotlib.pyplot as plt [](#__codelineno-0-2)plt.plot([1, 2]) [](#__codelineno-0-3)axis = plt.gca() [](#__codelineno-0-4)mo.md( [](#__codelineno-0-5) f""" [](#__codelineno-0-6) Here is a plot: [](#__codelineno-0-7) [](#__codelineno-0-8) {mo.as_html(axis)} [](#__codelineno-0-9) """ [](#__codelineno-0-10))` marimo.Html `dataclass` [¶](#marimo.Html "Permanent link") ---------------------------------------------------------- Bases: `MIME` A wrapper around HTML text that can be used as an output. Output an `Html` object as the last expression of a cell to render it in your app. Use f-strings to embed Html objects as text into other HTML or markdown strings. For example: `[](#__codelineno-0-1)hello_world = Html("

Hello, World

") [](#__codelineno-0-2)Html( [](#__codelineno-0-3) f''' [](#__codelineno-0-4)

Hello, Universe!

[](#__codelineno-0-5) {hello_world} [](#__codelineno-0-6) ''' [](#__codelineno-0-7))` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[text](#marimo.Html.text " text property (marimo.Html.text)")` | a string of HTML **TYPE:** `str` | | PARAMETER | DESCRIPTION | | --- | --- | | `text` | a string of HTML **TYPE:** `str` | | METHOD | DESCRIPTION | | --- | --- | | `[batch](#marimo.Html.batch " batch (marimo.Html.batch)")` | convert this HTML element into a batched UI element | | `[callout](#marimo.Html.callout " callout (marimo.Html.callout)")` | wrap this element in a callout | | `[center](#marimo.Html.center " center (marimo.Html.center)")` | center this element in the output area | | `[right](#marimo.Html.right " right (marimo.Html.right)")` | right-justify this element in the output area | Initialize the HTML element. Subclasses of HTML MUST call this method. ### text `property` [¶](#marimo.Html.text "Permanent link") A string of HTML representing this element. ### batch [¶](#marimo.Html.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.Html.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.Html.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### left [¶](#marimo.Html.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.Html.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.Html.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | marimo.iframe [¶](#marimo.iframe "Permanent link") -------------------------------------------------- `[](#__codelineno-0-1)iframe( [](#__codelineno-0-2) html: str, *, width: str = "100%", height: str = "400px" [](#__codelineno-0-3)) -> [Html](#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Embed an HTML string in an iframe. Scripts by default are not executed using `mo.as_html` or `mo.Html`, so if you have a script tag (written as ``), you can use `mo.iframe` for scripts to be executed. You may also want to use this function to display HTML content that may contain styles that could interfere with the rest of the page. Example `[](#__codelineno-0-1)html = "

Hello, world!

" [](#__codelineno-0-2)mo.iframe(html)` | PARAMETER | DESCRIPTION | | --- | --- | | `html` | An HTML string **TYPE:** `str` | | `width` | The width of the iframe **TYPE:** `str` **DEFAULT:** `'100%'` | | `height` | The height of the iframe **TYPE:** `str` **DEFAULT:** `'400px'` |
Query Parameters - marimo https://docs.marimo.io/api/query_params/ Query parameters are key-value pairs appended to the end of a URL to pass data to the server or customize a request. Use `mo.query_params` to access query parameters passed to the notebook. You can also use `mo.query_params` to set query parameters in order to keep track of state in the URL. This is useful for bookmarking or sharing a particular state of the notebook while running as an application with `marimo run`. marimo.query\_params [¶](#marimo.query_params "Permanent link") --------------------------------------------------------------- `[](#__codelineno-0-1)query_params() -> QueryParams` Get the query parameters of a marimo app. Examples: Keep the text input in sync with the URL query parameters: `[](#__codelineno-0-1)# In its own cell [](#__codelineno-0-2)query_params = mo.query_params() [](#__codelineno-0-3)[](#__codelineno-0-4)# In another cell [](#__codelineno-0-5)search = mo.ui.text( [](#__codelineno-0-6) value=query_params["search"] or "", [](#__codelineno-0-7) on_change=lambda value: query_params.set("search", value), [](#__codelineno-0-8)) [](#__codelineno-0-9)search` You can also set the query parameters reactively: `[](#__codelineno-1-1)toggle = mo.ui.switch(label="Toggle me") [](#__codelineno-1-2)toggle [](#__codelineno-1-3)[](#__codelineno-1-4)# In another cell [](#__codelineno-1-5)query_params["is_enabled"] = toggle.value` | RETURNS | DESCRIPTION | | --- | --- | | `QueryParams` | A QueryParams object containing the query parameters. You can directly interact with this object like a dictionary. If you mutate this object, changes will be persisted to the frontend query parameters and any other cells referencing the query parameters will automatically re-run. **TYPE:** `QueryParams` | Pydantic Models for Query Parameters[¶](#pydantic-models-for-query-parameters "Permanent link") ----------------------------------------------------------------------------------------------- One of the use cases for URL query parameters is to set the initial state of UI elements. Passing query parameters into a Pydantic model helps document and validate the parameters. `[](#__codelineno-0-1)import marimo as mo [](#__codelineno-0-2)from pydantic import BaseModel, Field [](#__codelineno-0-3)[](#__codelineno-0-4)class MyModel(BaseModel): [](#__codelineno-0-5) r: int = Field(28, ge=0, le=255, description="Red Channel") [](#__codelineno-0-6) g: int = Field(115, ge=0, le=255, description="Green Channel") [](#__codelineno-0-7) b: int = Field(97, ge=0, le=255, description="Blue Channel") [](#__codelineno-0-8) message: str = Field("
", description="Some text") [](#__codelineno-0-9)[](#__codelineno-0-10)model = MyModel(**mo.query_params().to_dict()) [](#__codelineno-0-11)[](#__codelineno-0-12)# UI with initial state from query params [](#__codelineno-0-13)r_slider = mo.ui.slider(start=0, stop=255, step=1, label="R", value=model.r) [](#__codelineno-0-14)g_slider = mo.ui.slider(start=0, stop=255, step=1, label="G", value=model.g) [](#__codelineno-0-15)b_slider = mo.ui.slider(start=0, stop=255, step=1, label="B", value=model.b)` In the next cell: (see [live](https://marimo.app/l/03egkc?g=255)) `[](#__codelineno-1-1)bg_color = f"rgb({r_slider.value},{g_slider.value},{b_slider.value})" [](#__codelineno-1-2)mo.vstack([ [](#__codelineno-1-3) r_slider, g_slider, b_slider, [](#__codelineno-1-4) mo.Html(model.message + bg_color).style(background_color=bg_color, text_align="center") [](#__codelineno-1-5)])` When using [marimo apps mounted to FastAPI](https://docs.marimo.io/guides/deploying/programmatically/), the Pydantic model can be passed into the API documentation for the main app. CLI arguments You can also access command-line arguments passed to the notebook using `mo.cli_args`. This allows you to pass arguments to the notebook that are not controllable by the user.
Diagrams - marimo https://docs.marimo.io/api/diagrams/ Render a diagram with Mermaid. Mermaid is a tool for making diagrams such as flow charts and graphs. See the [Mermaid documentation](https://github.com/mermaid-js/mermaid#readme) for details. | PARAMETER | DESCRIPTION | | --- | --- | | `diagram` | a string containing a Mermaid diagram **TYPE:** `str` | | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | Example `[](#__codelineno-0-1)diagram = ''' [](#__codelineno-0-2)graph LR [](#__codelineno-0-3) A[Square Rect] -- Link text --> B((Circle)) [](#__codelineno-0-4) A --> C(Round Rect) [](#__codelineno-0-5) B --> D{Rhombus} [](#__codelineno-0-6) C --> D [](#__codelineno-0-7)''' [](#__codelineno-0-8)mo.mermaid(diagram)` Command Line Arguments - marimo https://docs.marimo.io/api/cli_args/ When running as a script with `python notebook.py`, command-line arguments are available to your program in `sys.argv`, just like any other Python program. This means you can use [`argparse`](https://docs.python.org/3/library/argparse.html), [`simple-parsing`](https://github.com/lebrice/SimpleParsing), and other tools for specifying and parsing arguments. You can also use tools like `argparse` when running as a notebook (`marimo edit` or `marimo run`) or exporting to HTML, IPYNB or another format (`marimo export`). In these cases, `sys.argv` is set to the notebook filename followed by any args following the `--` separator. For example, for `[](#__codelineno-0-1)marimo edit notebook.py -- --lr 1e-4 --epochs 15` sets `sys.argv` to `["notebook.py", "--lr", "1e-4", "--epochs", "15"]`. For usage examples, see the guide on [running as a script](https://docs.marimo.io/guides/scripts/). Utility function for parsing arguments[¶](#utility-function-for-parsing-arguments "Permanent link") --------------------------------------------------------------------------------------------------- marimo provides a utility function called `mo.cli_args()` for parsing arguments from strings into primitive data types (`int`, `bool`, `float`, `str`). However, unlike `argparse` and `simple-parsing`, this function does not let you declare your program's arguments, nor does it generate help text. **For these reasons, we recommend using `argparse` or `simple-parsing` instead.** `[](#__codelineno-1-1)python notebook.py -- --arg1 value1 --arg2 value2 [](#__codelineno-1-2)# mo.cli_args() == {'arg1': 'value1', 'arg2': 'value2'} [](#__codelineno-1-3)[](#__codelineno-1-4)python notebook.py -- --arg1=10 --arg2=true --arg3 [](#__codelineno-1-5)# mo.cli_args() == {'arg1': 10, 'arg2': True, 'arg3': ''} [](#__codelineno-1-6)[](#__codelineno-1-7)python notebook.py -- --arg1 10.5 --arg2 hello --arg2 world [](#__codelineno-1-8)# mo.cli_args() == {'arg1': 10.5, 'arg2': ['hello', 'world']}` marimo.cli\_args [¶](#marimo.cli_args "Permanent link") ------------------------------------------------------- Get the command line arguments of a marimo notebook. Examples: `marimo edit notebook.py -- -size 10` `[](#__codelineno-0-1)# Access the command line arguments [](#__codelineno-0-2)size = mo.cli_args().get("size") or 100 [](#__codelineno-0-3)[](#__codelineno-0-4)for i in range(size): [](#__codelineno-0-5) print(i)` | RETURNS | DESCRIPTION | | --- | --- | | `CLIArgs` | A dictionary containing the command line arguments. This dictionary is read-only and cannot be mutated. **TYPE:** `CLIArgs` | Query Parameters You can also access query parameters passed to the notebook using `mo.query_params`. This allows you to pass arguments to the notebook that can be controlled by the user. Caching - marimo https://docs.marimo.io/api/caching/ marimo comes with utilities to cache intermediate computations. These utilities can be applied as decorators to functions to cache their returned values; you can choose between saving caches in memory or to disk. Basic usage[¶](#basic-usage "Permanent link") --------------------------------------------- marimo provides two decorators for caching the return values of expensive functions: 1. [`mo.cache`](#marimo.cache " marimo.cache"), which saves cached values to memory; 2. [`mo.persistent_cache`](#marimo.persistent_cache " marimo.persistent_cache"), which saves cached values to disk. `mo.cache``mo.persistent_cache``mo.cache` (async)`mo.persistent_cache` (async) `[](#__codelineno-0-1)import marimo as mo [](#__codelineno-0-2)[](#__codelineno-0-3)@mo.cache [](#__codelineno-0-4)def compute_embedding(data: str, embedding_dimension: int, model: str) -> np.ndarray: [](#__codelineno-0-5) ...` `[](#__codelineno-1-1)import marimo as mo [](#__codelineno-1-2)[](#__codelineno-1-3)@mo.persistent_cache [](#__codelineno-1-4)def compute_embedding(data: str, embedding_dimension: int, model: str) -> np.ndarray [](#__codelineno-1-5) ...` `[](#__codelineno-2-1)import marimo as mo [](#__codelineno-2-2)[](#__codelineno-2-3)@mo.cache [](#__codelineno-2-4)async def fetch_data(url: str, params: dict) -> dict: [](#__codelineno-2-5) response = await http_client.get(url, params=params) [](#__codelineno-2-6) return response.json()` `[](#__codelineno-3-1)import marimo as mo [](#__codelineno-3-2)[](#__codelineno-3-3)@mo.persistent_cache [](#__codelineno-3-4)async def compute_embedding(data: str, embedding_dimension: int, model: str) -> np.ndarray: [](#__codelineno-3-5) response = await llm_client.get_embeddings(data, model) [](#__codelineno-3-6) return response.embeddings` Roughly speaking, the first time a cached function is called with a particular sequence of arguments, the function will run and its return value will be cached. The next time it is called with the same sequence of arguments (on cache hit), the function body will be skipped and the return value will be retrieved from cache instead. The in-memory cache ([`mo.cache`](#marimo.cache " marimo.cache")) is faster and doesn't consume disk space, but it is lost on notebook restart. The disk cache ([`mo.persistent_cache`](#marimo.persistent_cache " marimo.persistent_cache")) is slower and consumes space on disk, but it persists across notebook runs, letting you pick up where you left off. (For an in-memory cache of bounded size, use [`mo.lru_cache`](#marimo.lru_cache " marimo.lru_cache").) Async functions are fully supported All cache decorators (`mo.cache`, `mo.lru_cache`, `mo.persistent_cache`) work seamlessly with both synchronous and asynchronous functions. When multiple concurrent calls are made to a cached async function with the same arguments, only one execution occurs—the rest await the result. This prevents race conditions and duplicate work. Where persistent caches are stored By default, persistent caches are stored in `__marimo__/cache/`, in the directory of the current notebook. For projects versioned with `git`, consider adding `**/__marimo__/cache/` to your `.gitignore`. Caches are preserved even when a cell is re-run If a cell defining a cached function is re-run, the cache will be preserved unless its source code (or the source code of the cell's ancestors) has changed. ### Persistent cache context manager[¶](#persistent-cache-context-manager "Permanent link") You can also use marimo's [`mo.persistent_cache`](#marimo.persistent_cache " marimo.persistent_cache") as a context manager: `[](#__codelineno-4-1)with mo.persistent_cache("my_cache_name"): [](#__codelineno-4-2) X = my_expensive_computation(data, model)` The next time this block of code is run, if marimo detects a cache hit, the code will be skipped and your variables will be loaded into memory. The cache key for the context manager is computed in the same way as it is computed for decorated functions. Cache key[¶](#cache-key "Permanent link") ----------------------------------------- Both `mo.cache` and `mo.persistent_cache` use the same mechanism for creating a cache key, differing only in where the cache is stored. The cache key is based on function arguments and closed-over variables. ### Function arguments[¶](#function-arguments "Permanent link") **Arguments must either be primitive, marimo UI elements, array-like, or pickleable:** 1. Primitive types (strings, bytes, numbers, None) are hashed. 2. marimo UI elements are hashed based on their value. 3. [Array-like objects](https://numpy.org/doc/stable/reference/arrays.interface.html#object.__array_interface__) are introspected, with their values being hashed. 4. All other objects are pickled. ### Closed-over variables[¶](#closed-over-variables "Permanent link") Syntactically closing over variables provides another way to parametrize functions. In this example, the variable `x` is "closed over": `[](#__codelineno-6-1)def my_function(): [](#__codelineno-6-2) return x + 1` Closed-over variables are processed in the following way: * marimo first attempts to hash or pickle the closed-over variables, just as it does for arguments. * If a closed-over variables cannot be hashed or pickled, then marimo uses the source code that defines the value as part of the cache key; in particular, marimo hashes the cell that defines the variable as well as the source code of that cell's ancestors. This assumes that the variable's value is a deterministic function of the source code that defines it, although certain side-effects (specifically, if a cell raised an exception or loaded from another cache) are taken into account. Because marimo's cache key construction can fall back to source code for closed-over variables, closing over variables lets you cache functions even in the presence of non-hashable and non-pickleable arguments. Limitations[¶](#limitations "Permanent link") --------------------------------------------- marimo's cache has some limitations: * Side effects are not cached. This means that on a cache hit, side effects like printing, file I/O, or network requests will not occur. * The source code of imported modules is not used when computing the cache key. * By setting `pin_modules` to `True`, you can ensure that the cache is invalidated when module versions change (`e.g.`, update when the module's `__version__` attribute changes). * This limitation does not apply if the external module is a marimo notebook. * The return values of persistently cached functions must be serializable with pickle. Don't mutate variables marimo works best when you don't mutate variables across cells. The same is true for caching, since the cache key may not always be able to take mutations into account. ### Decorators defined in other Python modules[¶](#decorators-defined-in-other-python-modules "Permanent link") Decorators defined in other Python modules that do not use `functools.wraps` cannot be correctly cached. This can lead to confusing bugs like the example below: `[](#__codelineno-7-1)# my_lib.py [](#__codelineno-7-2)def my_decorator(func): [](#__codelineno-7-3) def wrapper(*args, **kwargs): [](#__codelineno-7-4) return func(*args, **kwargs) [](#__codelineno-7-5) return wrapper` `[](#__codelineno-8-1)# Cell 1 [](#__codelineno-8-2)from my_lib import my_decorator [](#__codelineno-8-3)[](#__codelineno-8-4)@mo.cache [](#__codelineno-8-5)@my_decorator [](#__codelineno-8-6)def expensive_function(): [](#__codelineno-8-7) # ... some computation [](#__codelineno-8-8) return "result1" [](#__codelineno-8-9)[](#__codelineno-8-10)@mo.cache [](#__codelineno-8-11)@my_decorator [](#__codelineno-8-12)def another_expensive_function(): [](#__codelineno-8-13) # ... different computation [](#__codelineno-8-14) return "result2" [](#__codelineno-8-15)[](#__codelineno-8-16)# This assertion may unexpectedly pass due to cache collision! [](#__codelineno-8-17)assert expensive_function() == another_expensive_function(), "But why?"` The fix is to make sure the decorator uses `functools.wraps`: `[](#__codelineno-9-1)# my_lib.py (fixed) [](#__codelineno-9-2)from functools import wraps [](#__codelineno-9-3)[](#__codelineno-9-4)def my_decorator(func): [](#__codelineno-9-5) @wraps(func) [](#__codelineno-9-6) def wrapper(*args, **kwargs): [](#__codelineno-9-7) return func(*args, **kwargs) [](#__codelineno-9-8) return wrapper` In this instance, the cache will work as expected because the decorated function has the same signature and metadata as the original function. Here is a table comparing marimo's cache with `functools.cache`: | Feature | marimo cache | `functools.cache` | | --- | --- | --- | | Cache return values in memory? | ✅ | ✅ | | Cache return values to disk? | ✅ | ❌ | | Preserved on cell re-runs? | ✅ | ❌ | | Tracks closed-over variables | ✅ | ❌ | | Allows unhashable arguments? | ✅ | ❌ | | Allows Array-like arguments? | ✅ | ❌ | | Supports async functions? | ✅ | ❌ | | Suitable for lightweight functions (microseconds)? | ❌ | ✅ | When to use `functools.cache` Prefer `functools.cache` for extremely lightweight functions (that execute in less than a millisecond). Using memoization to calculate the Fibonacci sequence is a classic example of using `functools.cache` effectively. On a basic macbook in pure python, `fib(35)` takes 1 second to compute; with `mo.cache` it takes 0.000229 seconds; with `functools.cache`, it takes 0.000025 seconds (x9 faster!!). Although relatively small, the additional overhead of `mo.cache` (and more so `mo.persistent_cache`) is larger than `functools.cache`. If your function takes more than a few milliseconds to compute, the difference is negligible. Tips[¶](#tips "Permanent link") ------------------------------- ### Isolate cached code blocks to their own cells[¶](#isolate-cached-code-blocks-to-their-own-cells "Permanent link") Isolating cached functions in separate cells improves cache reliability. When dependencies and cached functions are in the same cell, any change to the cell invalidates the cache, even if the cached function itself hasn't changed. Separating them ensures the cache is only invalidated when the function actually changes. **Don't do this:** `[](#__codelineno-10-1)# Cell 1 [](#__codelineno-10-2)llm_client = ... [](#__codelineno-10-3)@mo.cache [](#__codelineno-10-4)def prompt_llm(query, **kwargs): [](#__codelineno-10-5) message = {"role": "user", "content": query} [](#__codelineno-10-6) return llm_client.chat.completions.create(messages=[message], **kwargs)` **Do this instead:** `[](#__codelineno-11-1)# Cell 1 [](#__codelineno-11-2)llm_client = ...` `[](#__codelineno-12-1)# Cell 2 [](#__codelineno-12-2)@mo.cache [](#__codelineno-12-3)def prompt_llm(query, **kwargs): [](#__codelineno-12-4) message = {"role": "user", "content": query} [](#__codelineno-12-5) return llm_client.chat.completions.create(messages=[message], **kwargs)` ### Close over unhashable or un-pickleable arguments[¶](#close-over-unhashable-or-un-pickleable-arguments "Permanent link") The [cache key](#cache-key) is constructed in part by hashing or pickle-ing function arguments. When you call a cached function with arguments that cannot be processed in this way, an exception will be raised. To parametrize cached functions with unhashable or un-pickleable arguments, syntactically close over them instead. **You can't do this:** `[](#__codelineno-13-1)# Cell 1 [](#__codelineno-13-2)@mo.cache [](#__codelineno-13-3)def query_database(query, engine): [](#__codelineno-13-4) return engine.execute(query)` `[](#__codelineno-14-1)# This won't work because my_database_engine is not hashable [](#__codelineno-14-2)query_database("SELECT * FROM my_table", my_database_engine)` Instead, you can close over `my_database_engine`: **Do this:** `[](#__codelineno-15-1)# Cell 1 [](#__codelineno-15-2)my_database_engine = ...` `[](#__codelineno-16-1)# Cell 2 [](#__codelineno-16-2)@mo.cache [](#__codelineno-16-3)def query_database(query): [](#__codelineno-16-4) return my_database_engine.execute(query)` ### Close-over low-memory-footprint variables[¶](#close-over-low-memory-footprint-variables "Permanent link") Non-primitive closed-over variables are serialized for cache key generation. When possible, compute derived values (like length) outside the cache block and only use the small values inside. **Don't do this:** `[](#__codelineno-17-1)with mo.persistent_cache("bad example"): [](#__codelineno-17-2) length = len(my_very_large_dataset) [](#__codelineno-17-3) ... # uses length` **Do this instead:** `[](#__codelineno-18-1)length = len(my_very_large_dataset) # my_very_large_dataset is not needed for cache invalidation` `[](#__codelineno-19-1)with mo.persistent_cache("good example"): [](#__codelineno-19-2) ... # uses length` ### Use `mo.watch.file` when working with files[¶](#use-mowatchfile-when-working-with-files "Permanent link") **Don't do this:** `[](#__codelineno-20-1)my_file = open("my_file.txt") [](#__codelineno-20-2)with mo.persistent_cache("my_file"): [](#__codelineno-20-3) data = my_file.read() [](#__codelineno-20-4) # Do something with data [](#__codelineno-20-5)my_file.close()` **Do this instead:** `[](#__codelineno-21-1)# Cell 1 [](#__codelineno-21-2)my_file = mo.watch.file("my_file.txt")` `[](#__codelineno-22-1)# Cell 2 [](#__codelineno-22-2)with mo.persistent_cache("my_file"): [](#__codelineno-22-3) data = my_file.read() [](#__codelineno-22-4) # Do something with data` API[¶](#api "Permanent link") ----------------------------- marimo.cache [¶](#marimo.cache "Permanent link") ------------------------------------------------ `[](#__codelineno-0-1)cache( [](#__codelineno-0-2) fn: Callable[P, Coroutine[Any, Any, R]], [](#__codelineno-0-3) pin_modules: bool = False, [](#__codelineno-0-4) loader: LoaderPartial | LoaderType = MemoryLoader, [](#__codelineno-0-5)) -> _cache_call_async[P, R]` `[](#__codelineno-0-1)cache( [](#__codelineno-0-2) fn: Callable[P, R], [](#__codelineno-0-3) pin_modules: bool = False, [](#__codelineno-0-4) loader: LoaderPartial | LoaderType = MemoryLoader, [](#__codelineno-0-5)) -> _cache_call[P, R]` `[](#__codelineno-0-1)cache( [](#__codelineno-0-2) fn: None = None, [](#__codelineno-0-3) pin_modules: bool = False, [](#__codelineno-0-4) loader: LoaderPartial | LoaderType = MemoryLoader, [](#__codelineno-0-5)) -> _cache_call[Any, Any]` `[](#__codelineno-0-1)cache( [](#__codelineno-0-2) name: str, [](#__codelineno-0-3) pin_modules: bool = False, [](#__codelineno-0-4) loader: LoaderPartial [](#__codelineno-0-5) | Loader [](#__codelineno-0-6) | LoaderType = MemoryLoader, [](#__codelineno-0-7)) -> _cache_context` `[](#__codelineno-0-1)cache( [](#__codelineno-0-2) name: str | (Callable[..., Any] | None) = None, [](#__codelineno-0-3) *args: Any, [](#__codelineno-0-4) pin_modules: bool = False, [](#__codelineno-0-5) loader: LoaderPartial | Loader | None = None, [](#__codelineno-0-6) _frame_offset: int = 1, [](#__codelineno-0-7) _internal_interface_not_for_external_use: None = None, [](#__codelineno-0-8) **kwargs: Any, [](#__codelineno-0-9)) -> ( [](#__codelineno-0-10) _cache_call[Any, Any] [](#__codelineno-0-11) | _cache_call_async[Any, Any] [](#__codelineno-0-12) | _cache_context [](#__codelineno-0-13))` #### Cache the value of a function based on args and closed-over variables.[¶](#marimo.cache--cache-the-value-of-a-function-based-on-args-and-closed-over-variables "Permanent link") Decorating a function with `@mo.cache` will cache its value based on the function's arguments, closed-over values, and the notebook code. Examples: `[](#__codelineno-0-1)import marimo as mo [](#__codelineno-0-2) [](#__codelineno-0-3)[](#__codelineno-0-4)@mo.cache [](#__codelineno-0-5)def fib(n): [](#__codelineno-0-6) if n <= 1: [](#__codelineno-0-7) return n [](#__codelineno-0-8) return fib(n - 1) + fib(n - 2)` `mo.cache` is similar to `functools.cache`, but with three key benefits: 1. `mo.cache` persists its cache even if the cell defining the cached function is re-run, as long as the code defining the function and ancestors (excluding comments and formatting) has not changed. 2. `mo.cache` keys on closed-over values in addition to function arguments, preventing accumulation of hidden state associated with `functools.cache`. 3. `mo.cache` does not require its arguments to be hashable (only pickleable), meaning it can work with lists, sets, NumPy arrays, PyTorch tensors, and more. `mo.cache` obtains these benefits at the cost of slightly higher overhead than `functools.cache`, so it is best used for expensive functions. Like `functools.cache`, `mo.cache` is thread-safe. The cache has an unlimited maximum size. To limit the cache size, use `@mo.lru_cache`. `mo.cache` is slightly faster than `mo.lru_cache`, but in most applications the difference is negligible. Note, `mo.cache` can also be used as a drop in replacement for context block caching like `mo.persistent_cache`. | PARAMETER | DESCRIPTION | | --- | --- | | `pin_modules` | if True, the cache will be invalidated if module versions differ. **TYPE:** `bool` **DEFAULT:** `False` | #### Context manager to cache the return value of a block of code.[¶](#marimo.cache--context-manager-to-cache-the-return-value-of-a-block-of-code "Permanent link") The `mo.cache` context manager lets you delimit a block of code in which variables will be cached to memory when they are first computed. By default, the cache is stored in memory and is not persisted across kernel runs, for that functionality, refer to `mo.persistent_cache`. Examples: `[](#__codelineno-0-1)with mo.cache("my_cache") as cache: [](#__codelineno-0-2) variable = expensive_function()` | PARAMETER | DESCRIPTION | | --- | --- | | `name` | the name of the cache, used to set saving path- to manually invalidate the cache, change the name. **TYPE:** `str | (Callable[..., Any] | None)` **DEFAULT:** `None` | | `pin_modules` | if True, the cache will be invalidated if module versions differ. **TYPE:** `bool` **DEFAULT:** `False` | | `loader` | the loader to use for the cache, defaults to `MemoryLoader`. **TYPE:** `LoaderPartial | Loader | None` **DEFAULT:** `None` | | `**kwargs` | keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | | `*args` | positional arguments **TYPE:** `Any` **DEFAULT:** `()` | marimo.lru\_cache [¶](#marimo.lru_cache "Permanent link") --------------------------------------------------------- `[](#__codelineno-0-1)lru_cache( [](#__codelineno-0-2) fn: Callable[P, Coroutine[Any, Any, R]], [](#__codelineno-0-3) maxsize: int = 128, [](#__codelineno-0-4) pin_modules: bool = False, [](#__codelineno-0-5)) -> _cache_call_async[P, R]` `[](#__codelineno-0-1)lru_cache( [](#__codelineno-0-2) fn: Callable[P, R], [](#__codelineno-0-3) maxsize: int = 128, [](#__codelineno-0-4) pin_modules: bool = False, [](#__codelineno-0-5)) -> _cache_call[P, R]` `[](#__codelineno-0-1)lru_cache( [](#__codelineno-0-2) fn: None = None, [](#__codelineno-0-3) maxsize: int = 128, [](#__codelineno-0-4) pin_modules: bool = False, [](#__codelineno-0-5)) -> _cache_call[Any, Any]` `[](#__codelineno-0-1)lru_cache( [](#__codelineno-0-2) name: str, maxsize: int = 128, pin_modules: bool = False [](#__codelineno-0-3)) -> _cache_context` `[](#__codelineno-0-1)lru_cache( [](#__codelineno-0-2) name: str | (Callable[..., Any] | None) = None, [](#__codelineno-0-3) maxsize: int = 128, [](#__codelineno-0-4) *args: Any, [](#__codelineno-0-5) pin_modules: bool = False, [](#__codelineno-0-6) _internal_interface_not_for_external_use: None = None, [](#__codelineno-0-7) **kwargs: Any, [](#__codelineno-0-8)) -> ( [](#__codelineno-0-9) _cache_call[Any, Any] [](#__codelineno-0-10) | _cache_call_async[Any, Any] [](#__codelineno-0-11) | _cache_context [](#__codelineno-0-12))` Decorator for LRU caching the return value of a function. `mo.lru_cache` is a version of `mo.cache` with a bounded cache size. As an LRU (Least Recently Used) cache, only the last used `maxsize` values are retained, with the oldest values being discarded. For more information, see the documentation of `mo.cache`. Examples: `[](#__codelineno-0-1)import marimo as mo [](#__codelineno-0-2) [](#__codelineno-0-3)[](#__codelineno-0-4)@mo.lru_cache [](#__codelineno-0-5)def factorial(n): [](#__codelineno-0-6) return n * factorial(n - 1) if n else 1` | PARAMETER | DESCRIPTION | | --- | --- | | `maxsize` | the maximum number of entries in the cache; defaults to 128. Setting to -1 disables cache limits. **TYPE:** `int` **DEFAULT:** `128` | | `pin_modules` | if True, the cache will be invalidated if module versions differ. **TYPE:** `bool` **DEFAULT:** `False` | #### Context manager for LRU caching the return value of a block of code.[¶](#marimo.lru_cache--context-manager-for-lru-caching-the-return-value-of-a-block-of-code "Permanent link") | PARAMETER | DESCRIPTION | | --- | --- | | `name` | Namespace key for the cache. **TYPE:** `str | (Callable[..., Any] | None)` **DEFAULT:** `None` | | `maxsize` | the maximum number of entries in the cache; defaults to 128. Setting to -1 disables cache limits. **TYPE:** `int` **DEFAULT:** `128` | | `pin_modules` | if True, the cache will be invalidated if module versions differ. **TYPE:** `bool` **DEFAULT:** `False` | | `**kwargs` | keyword arguments passed to `cache()` **TYPE:** `Any` **DEFAULT:** `{}` | | `*args` | positional arguments passed to `cache()` **TYPE:** `Any` **DEFAULT:** `()` | marimo.persistent\_cache [¶](#marimo.persistent_cache "Permanent link") ----------------------------------------------------------------------- `[](#__codelineno-0-1)persistent_cache( [](#__codelineno-0-2) fn: Callable[P, Coroutine[Any, Any, R]], [](#__codelineno-0-3) save_path: str | None = None, [](#__codelineno-0-4) method: LoaderKey = "pickle", [](#__codelineno-0-5) pin_modules: bool = False, [](#__codelineno-0-6)) -> _cache_call_async[P, R]` `[](#__codelineno-0-1)persistent_cache( [](#__codelineno-0-2) fn: Callable[P, R], [](#__codelineno-0-3) save_path: str | None = None, [](#__codelineno-0-4) method: LoaderKey = "pickle", [](#__codelineno-0-5) pin_modules: bool = False, [](#__codelineno-0-6)) -> _cache_call[P, R]` `[](#__codelineno-0-1)persistent_cache( [](#__codelineno-0-2) fn: None = None, [](#__codelineno-0-3) save_path: str | None = None, [](#__codelineno-0-4) method: LoaderKey = "pickle", [](#__codelineno-0-5) pin_modules: bool = False, [](#__codelineno-0-6)) -> _cache_call[Any, Any]` `[](#__codelineno-0-1)persistent_cache( [](#__codelineno-0-2) name: str, [](#__codelineno-0-3) save_path: str | None = None, [](#__codelineno-0-4) method: LoaderKey = "pickle", [](#__codelineno-0-5) pin_modules: bool = False, [](#__codelineno-0-6)) -> _cache_context` `[](#__codelineno-0-1)persistent_cache( [](#__codelineno-0-2) name: str | (Callable[..., Any] | None) = None, [](#__codelineno-0-3) save_path: str | None = None, [](#__codelineno-0-4) method: LoaderKey = "pickle", [](#__codelineno-0-5) store: Store | None = None, [](#__codelineno-0-6) fn: Callable[..., Any] | None = None, [](#__codelineno-0-7) *args: Any, [](#__codelineno-0-8) pin_modules: bool = False, [](#__codelineno-0-9) _internal_interface_not_for_external_use: None = None, [](#__codelineno-0-10) **kwargs: Any, [](#__codelineno-0-11)) -> ( [](#__codelineno-0-12) _cache_call[Any, Any] [](#__codelineno-0-13) | _cache_call_async[Any, Any] [](#__codelineno-0-14) | _cache_context [](#__codelineno-0-15))` #### Context manager to save variables to disk and restore them thereafter.[¶](#marimo.persistent_cache--context-manager-to-save-variables-to-disk-and-restore-them-thereafter "Permanent link") The `mo.persistent_cache` context manager lets you delimit a block of code in which variables will be cached to disk when they are first computed. On subsequent runs of the cell, if marimo determines that this block of code hasn't changed and neither has its ancestors, it will restore the variables from disk instead of re-computing them, skipping execution of the block entirely. Restoration happens even across notebook runs, meaning you can use `mo.persistent_cache` to make notebooks start _instantly_, with variables that would otherwise be expensive to compute already materialized in memory. Examples: `[](#__codelineno-0-1)with persistent_cache(name="my_cache"): [](#__codelineno-0-2) variable = expensive_function() # This will be cached to disk. [](#__codelineno-0-3) print("hello, cache") # this will be skipped on cache hits` In this example, `variable` will be cached the first time the block is executed, and restored on subsequent runs of the block. If cache conditions are hit, the contents of `with` block will be skipped on execution. This means that side-effects such as writing to stdout and stderr will be skipped on cache hits. Note that `mo.state` and `UIElement` changes will also trigger cache invalidation, and be accordingly updated. **Warning.** Since context abuses sys frame trace, this may conflict with debugging tools or libraries that also use `sys.settrace`. #### Decorator for persistently caching the return value of a function.[¶](#marimo.persistent_cache--decorator-for-persistently-caching-the-return-value-of-a-function "Permanent link") `persistent_cache` can also be used as a drop in function-level memoization for `@mo.cache` or `@mo.lru_cache`. This is much slower than cache, but can be useful for saving function values between kernel restarts. For more details, refer to `mo.cache`. **Usage.** `[](#__codelineno-1-1)import marimo as mo [](#__codelineno-1-2) [](#__codelineno-1-3)[](#__codelineno-1-4)@mo.persistent_cache [](#__codelineno-1-5)def my_expensive_function(): [](#__codelineno-1-6) # Do expensive things [](#__codelineno-1-7)[](#__codelineno-1-8)# or [](#__codelineno-1-9)[](#__codelineno-1-10)@mo.persistent_cache(save_path="my/path/to/cache") [](#__codelineno-1-11)def my_expensive_function_cached_in_a_certain_location(): [](#__codelineno-1-12) # Do expensive things` | PARAMETER | DESCRIPTION | | --- | --- | | `name` | the name of the cache, used to set saving path- to manually invalidate the cache, change the name. **TYPE:** `str | (Callable[..., Any] | None)` **DEFAULT:** `None` | | `save_path` | the folder in which to save the cache, defaults to `__marimo__/cache` in the directory of the notebook file **TYPE:** `str | None` **DEFAULT:** `None` | | `method` | the serialization method to use, current options are "json", and "pickle" (default). **TYPE:** `LoaderKey` **DEFAULT:** `'pickle'` | | `store` | optional store. **TYPE:** `Store | None` **DEFAULT:** `None` | | `fn` | the wrapped function if no settings are passed. **TYPE:** `Callable[..., Any] | None` **DEFAULT:** `None` | | `*args` | positional arguments passed to `cache()` **TYPE:** `Any` **DEFAULT:** `()` | | `pin_modules` | if True, the cache will be invalidated if module versions differ between runs, defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `**kwargs` | keyword arguments passed to `cache()` **TYPE:** `Any` **DEFAULT:** `{}` | State - marimo https://docs.marimo.io/api/state/ Advanced topic! This guide covers reactive state (`mo.state`), an advanced topic. **You likely don't need `mo.state`**. UI elements already have built-in state, their associated value, which you can access with their `value` attribute. For example, `mo.ui.slider()` has a value that is its current position on an interval, while `mo.ui.button()` has a value that can be configured to count the number of times it has been clicked, or to toggle between `True` and `False`. Additionally, interacting with UI elements bound to global variables [automatically executes cells](https://docs.marimo.io/guides/interactivity/) that reference those variables, letting you react to changes by just reading their `value` attributes. **This functional paradigm is the preferred way of reacting to UI interactions in marimo.** **Chances are, the reactive execution built into UI elements will suffice.** (For example, [you don't need reactive state to handle a button click](https://docs.marimo.io/recipes/#working-with-buttons).) That said, here are some signs you might need `mo.state`: * you need to maintain historical state related to a UI element that can't be computed from its built-in `value` (_e.g._, all values the user has ever input into a form) * you need to synchronize two different UI elements (_e.g._, so that interacting with either one controls the other) * you need to introduce cycles across cells **In over 99% of cases, you don't need and shouldn't use `mo.state`.** This feature can introduce hard-to-find bugs. marimo.state [¶](#marimo.state "Permanent link") ------------------------------------------------ `[](#__codelineno-0-1)state( [](#__codelineno-0-2) value: T, allow_self_loops: bool = False [](#__codelineno-0-3)) -> tuple[State[T], Callable[[T], None]]` Mutable reactive state. Warning: reactive state is an advanced feature that you likely don't need; it makes it possible to introduce cycles and hard-to-debug code execution paths. **In almost all cases, you should prefer using marimo's built-in [reactive execution](https://docs.marimo.io/guides/reactivity) and [interactivity](https://docs.marimo.io/guides/interactivity).** 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, set the keyword argument `allow_self_loops=True`. You can use this function with `UIElement` `on_change` handlers to trigger side-effects when an element's value is updated; however, you should prefer using marimo's built-in [reactive execution for interactive elements](https://docs.marimo.io/guides/interactivity). For example, you can tie multiple UI elements to derive their values from shared state. Examples: Create state: `[](#__codelineno-0-1)get_count, set_count = mo.state(0)` Read the value: Update the state: Update based on current value: `[](#__codelineno-3-1)set_count(lambda value: value + 1)` Never mutate the state directly. You should only change its value through its setter. **Synchronizing multiple UI elements:** `[](#__codelineno-0-1)get_state, set_state = mo.state(0)` `[](#__codelineno-1-1)# Updating the state through the slider will recreate the number (below) [](#__codelineno-1-2)slider = mo.ui.slider(0, 100, value=get_state(), on_change=set_state)` `[](#__codelineno-2-1)# Updating the state through the number will recreate the slider (above) [](#__codelineno-2-2)number = mo.ui.number(0, 100, value=get_state(), on_change=set_state)` `[](#__codelineno-3-1)# slider and number are synchronized to have the same value (try it!) [](#__codelineno-3-2)[slider, number]` Warning Do not store `marimo.ui` elements in state; doing so can cause hard-to-diagnose bugs. | PARAMETER | DESCRIPTION | | --- | --- | | `value` | Initial value of the state. **TYPE:** `T` | | `allow_self_loops` | If True, a cell that calls a state setter and also references its getter will be re-run. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | RETURNS | DESCRIPTION | | --- | --- | | `State[T]` | A tuple of (getter function, setter function). The getter function | | `Callable[[T], None]` | retrieves the state value; the setter function takes a new value or a | | `tuple[State[T], Callable[[T], None]]` | function that updates the current value. | App - marimo https://docs.marimo.io/api/app/ Embed a notebook into another notebook. The `embed` method lets you embed the output of a notebook into another notebook and access the values of its variables. Running `await app.embed()` executes the notebook and results an object encapsulating the notebook visual output and its definitions. Embedded notebook outputs are interactive: when you interact with UI elements in an embedded notebook's output, any cell referring to the `app` object other than the one that imported it is marked for execution, and its internal state is automatically updated. This lets you use notebooks as building blocks or components to create higher-level notebooks. Multiple levels of nesting are supported: it's possible to embed a notebook that in turn embeds another notebook, and marimo will do the right thing. Example `[](#__codelineno-0-1)from my_notebook import app` `[](#__codelineno-1-1)# execute the notebook; app.embed() can't be called in the cell [](#__codelineno-1-2)# that imported it! [](#__codelineno-1-3)result = await app.embed()` `[](#__codelineno-2-1)# view the notebook's visual output [](#__codelineno-2-2)result.output` `[](#__codelineno-3-1)# access the notebook's defined variables [](#__codelineno-3-2)result.defs` To embed independent copies of same app object, first clone the app with `app.clone()`: ` ```python from my_notebook import app ``` ```python one = app.clone() ``` ```python r1 = await one.embed() ``` ```python two = app.clone() ``` ```python r2 = await two.embed() ``` ` | PARAMETER | DESCRIPTION | | --- | --- | | `defs` | You may pass values for any variable definitions as keyword arguments. marimo will use these values instead of executing the cells that would normally define them. Cells that depend on these variables will use your provided values. **TYPE:** `dict[str, Any]` **DEFAULT:** `None` | | RETURNS | DESCRIPTION | | --- | --- | | `AppEmbedResult` | An object `result` with two attributes: `result.output` (visual | | `AppEmbedResult` | output of the notebook) and `result.defs` (a dictionary mapping | | `AppEmbedResult` | variable names defined by the notebook to their values). | Cell - marimo https://docs.marimo.io/api/cell/ Run this cell and return its visual output and definitions. Use this method to run **named cells** and retrieve their output and definitions. This lets you reuse cells defined in one notebook in another notebook or Python file. It also makes it possible to write and execute unit tests for notebook cells using a test framework like `pytest`. Examples: marimo cells can be given names either through the editor cell menu or by manually changing the function name in the notebook file. For example, consider a notebook `notebook.py`: `[](#__codelineno-0-1)import marimo [](#__codelineno-0-2)[](#__codelineno-0-3)app = marimo.App() [](#__codelineno-0-4) [](#__codelineno-0-5)[](#__codelineno-0-6)@app.cell [](#__codelineno-0-7)def _(): [](#__codelineno-0-8) import marimo as mo [](#__codelineno-0-9) [](#__codelineno-0-10) return (mo,) [](#__codelineno-0-11) [](#__codelineno-0-12)[](#__codelineno-0-13)@app.cell [](#__codelineno-0-14)def _(): [](#__codelineno-0-15) x = 0 [](#__codelineno-0-16) y = 1 [](#__codelineno-0-17) return (x, y) [](#__codelineno-0-18) [](#__codelineno-0-19)[](#__codelineno-0-20)@app.cell [](#__codelineno-0-21)def add(mo, x, y): [](#__codelineno-0-22) z = x + y [](#__codelineno-0-23) mo.md(f"The value of z is {z}") [](#__codelineno-0-24) return (z,) [](#__codelineno-0-25) [](#__codelineno-0-26)[](#__codelineno-0-27)if __name__ == "__main__": [](#__codelineno-0-28) app.run()` To reuse the `add` cell in another notebook, you'd simply write: ``[](#__codelineno-1-1)from notebook import add [](#__codelineno-1-2)[](#__codelineno-1-3)# `output` is the markdown rendered by `add` [](#__codelineno-1-4)# defs["z"] == `1` [](#__codelineno-1-5)output, defs = add.run()`` When `run` is called without arguments, it automatically computes the values that the cell depends on (in this case, `mo`, `x`, and `y`). You can override these values by providing any subset of them as keyword arguments. For example, `[](#__codelineno-2-1)# defs["z"] == 4 [](#__codelineno-2-2)output, defs = add.run(x=2, y=2)` Defined UI Elements If the cell's `output` has UI elements that are in `defs`, interacting with the output in the frontend will trigger reactive execution of cells that reference the `defs` object. For example, if `output` has a slider defined by the cell, then scrubbing the slider will cause cells that reference `defs` to run. Async cells If this cell is a coroutine function (starting with `async`), or if any of its ancestors are coroutine functions, then you'll need to `await` the result: `output, defs = await cell.run()`. You can check whether the result is an awaitable using: `[](#__codelineno-0-1)from collections.abc import Awaitable [](#__codelineno-0-2)[](#__codelineno-0-3)ret = cell.run() [](#__codelineno-0-4)if isinstance(ret, Awaitable): [](#__codelineno-0-5) output, defs = await ret [](#__codelineno-0-6)else: [](#__codelineno-0-7) output, defs = ret` | PARAMETER | DESCRIPTION | | --- | --- | | `**refs` | You may pass values for any of this cell's references as keyword arguments. marimo will automatically compute values for any refs that are not provided by executing the parent cells that compute them. **TYPE:** `Any` **DEFAULT:** `{}` | | RETURNS | DESCRIPTION | | --- | --- | | `tuple[Any, Mapping[str, Any]] | Awaitable[tuple[Any, Mapping[str, Any]]]` | tuple `(output, defs)`, or an awaitable of the same: `output` is the cell's last expression and `defs` is a `Mapping` from the cell's defined names to their values. | Miscellaneous - marimo https://docs.marimo.io/api/miscellaneous/ marimo.running\_in\_notebook [¶](#marimo.running_in_notebook "Permanent link") ------------------------------------------------------------------------------ `[](#__codelineno-0-1)running_in_notebook() -> bool` Returns True if running in a marimo notebook, False otherwise marimo.defs [¶](#marimo.defs "Permanent link") ---------------------------------------------- `[](#__codelineno-0-1)defs() -> tuple[str, ...]` Get the definitions of the currently executing cell. | RETURNS | DESCRIPTION | | --- | --- | | `tuple[str, ...]` | tuple\[str, ...\]: A tuple of the currently executing cell's defs. | marimo.refs [¶](#marimo.refs "Permanent link") ---------------------------------------------- `[](#__codelineno-0-1)refs() -> tuple[str, ...]` Get the references of the currently executing cell. | RETURNS | DESCRIPTION | | --- | --- | | `tuple[str, ...]` | tuple\[str, ...\]: A tuple of the currently executing cell's refs. | marimo.notebook\_dir [¶](#marimo.notebook_dir "Permanent link") --------------------------------------------------------------- `[](#__codelineno-0-1)notebook_dir() -> Path | None` Get the directory of the currently executing notebook. | RETURNS | DESCRIPTION | | --- | --- | | `Path | None` | pathlib.Path | None: A pathlib.Path object representing the directory of the current notebook, or None if the notebook's directory cannot be determined. | Examples: `[](#__codelineno-0-1)data_file = mo.notebook_dir() / "data" / "example.csv" [](#__codelineno-0-2)# Use the directory to read a file [](#__codelineno-0-3)if data_file.exists(): [](#__codelineno-0-4) print(f"Found data file: {data_file}") [](#__codelineno-0-5)else: [](#__codelineno-0-6) print("No data file found")` marimo.notebook\_location [¶](#marimo.notebook_location "Permanent link") ------------------------------------------------------------------------- `[](#__codelineno-0-1)notebook_location() -> PurePath | None` Get the location of the currently executing notebook. In WASM, this is the URL of webpage, for example, `https://my-site.com`. For nested paths, this is the URL including the origin and pathname. `https://.github.io//folder`. In non-WASM, this is the directory of the notebook, which is the same as `mo.notebook_dir()`. Examples: In order to access data both locally and when a notebook runs via WebAssembly (e.g. hosted on GitHub Pages), you can use this approach to fetch data from the notebook's location. `[](#__codelineno-0-1)import polars as pl [](#__codelineno-0-2)[](#__codelineno-0-3)data_path = mo.notebook_location() / "public" / "data.csv" [](#__codelineno-0-4)df = pl.read_csv(str(data_path)) [](#__codelineno-0-5)df.head()` | RETURNS | DESCRIPTION | | --- | --- | | `PurePath | None` | Path | None: A Path object representing the URL or directory of the current notebook, or None if the notebook's directory cannot be determined. | Inspect[¶](#inspect "Permanent link") ------------------------------------- Use `mo.inspect()` to explore Python objects with a rich, interactive display of their attributes, methods, and documentation. ### Example[¶](#example "Permanent link") `[](#__codelineno-0-1)import marimo as mo [](#__codelineno-0-2)[](#__codelineno-0-3)# Inspect a class [](#__codelineno-0-4)mo.inspect(list, methods=True) [](#__codelineno-0-5)[](#__codelineno-0-6)# Inspect an instance [](#__codelineno-0-7)my_dict = {"key": "value"} [](#__codelineno-0-8)mo.inspect(my_dict) [](#__codelineno-0-9)[](#__codelineno-0-10)# Show all attributes including private and dunder [](#__codelineno-0-11)mo.inspect(my_dict, all=True)` marimo.inspect [¶](#marimo.inspect "Permanent link") ---------------------------------------------------- `[](#__codelineno-0-1)inspect( [](#__codelineno-0-2) obj: object, [](#__codelineno-0-3) *, [](#__codelineno-0-4) help: bool = False, [](#__codelineno-0-5) methods: bool = False, [](#__codelineno-0-6) docs: bool = True, [](#__codelineno-0-7) private: bool = False, [](#__codelineno-0-8) dunder: bool = False, [](#__codelineno-0-9) sort: bool = True, [](#__codelineno-0-10) all: bool = False, [](#__codelineno-0-11) value: bool = True, [](#__codelineno-0-12))` Bases: `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Inspect a Python object. Displays objects with their attributes, methods, and documentation in a rich HTML format. Useful for exploring objects that lack a rich repr. | PARAMETER | DESCRIPTION | | --- | --- | | `obj` | The object to inspect. **TYPE:** `object` | | `help` | Show full help text (otherwise just first paragraph). **TYPE:** `bool` **DEFAULT:** `False` | | `methods` | Show methods. **TYPE:** `bool` **DEFAULT:** `False` | | `docs` | Show documentation for attributes/methods. **TYPE:** `bool` **DEFAULT:** `True` | | `private` | Show private attributes (starting with '\_'). **TYPE:** `bool` **DEFAULT:** `False` | | `dunder` | Show dunder attributes (starting with '\_\_'). **TYPE:** `bool` **DEFAULT:** `False` | | `sort` | Sort attributes alphabetically. **TYPE:** `bool` **DEFAULT:** `True` | | `all` | Show all attributes (methods, private, and dunder). **TYPE:** `bool` **DEFAULT:** `False` | | `value` | Show the object's value/repr. **TYPE:** `bool` **DEFAULT:** `True` | | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | Example `[](#__codelineno-0-1)mo.inspect(obj, methods=True)` ### text `property` [¶](#marimo.inspect.text "Permanent link") A string of HTML representing this element. ### batch [¶](#marimo.inspect.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.inspect.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.inspect.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### left [¶](#marimo.inspect.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.inspect.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.inspect.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/api/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Watch - marimo https://docs.marimo.io/api/watch/ A reactive wrapper for file paths. This function takes a file path to watch and returns a wrapper to reactively read and write from the file. The "wrapped" file Path object exposes most of the same methods as the [pathlib.Path object](https://docs.python.org/3/library/pathlib.html#pathlib.Path), with a few exceptions. The following methods are not available: * `open()` * `rename()` * `replace()` This object will trigger dependent cells to re-evaluate when the file is changed. Warning It is possible to misuse this API in similar ways to `state()`. Consider reading the warning and caveats in the [`state()` documentation](https://docs.marimo.io/api/state/), and using this function only when reading file paths, and not when writing them. | PARAMETER | DESCRIPTION | | --- | --- | | `path` | Path to watch. **TYPE:** `Path | str` | | RETURNS | DESCRIPTION | | --- | --- | | `FileState` | A reactive wrapper for watching the file path. | BigQuery - marimo https://docs.marimo.io/integrations/google_cloud_bigquery/ Google Cloud BigQuery[¶](#google-cloud-bigquery "Permanent link") ----------------------------------------------------------------- Getting Started[¶](#getting-started "Permanent link") ----------------------------------------------------- To use Google Cloud BigQuery as a data source, you will need to install the `google-cloud-bigquery` Python package. You can install this package using `pip`: `[](#__codelineno-0-1)pip install google-cloud-bigquery db-dtypes` Authentication[¶](#authentication "Permanent link") --------------------------------------------------- ### Application Default Credentials (Recommended)[¶](#application-default-credentials-recommended "Permanent link") The easiest way to authenticate with Google Cloud BigQuery is to use [Application Default Credentials](https://cloud.google.com/docs/authentication/production). If you are running marimo on Google Cloud and your resource has a service account attached, then Application Default Credentials will automatically be used. If you are running marimo locally, you can authenticate with Application Default Credentials by running the following command: `[](#__codelineno-1-1)gcloud auth application-default login` ### Service Account Key File[¶](#service-account-key-file "Permanent link") To authenticate with Google Cloud BigQuery, you will need to create a service account and download the service account key file. You can create a service account and download the key file by following the instructions [here](https://cloud.google.com/iam/docs/creating-managing-service-account-keys). Once you have downloaded the key file, you can authenticate with Google Cloud BigQuery by setting the `GOOGLE_APPLICATION_CREDENTIALS` environment variable to the path of the key file: `[](#__codelineno-2-1)export GOOGLE_APPLICATION_CREDENTIALS=/path/to/key/file.json` Reading Data[¶](#reading-data "Permanent link") ----------------------------------------------- To read data from Google Cloud BigQuery, you will need to create a `BigQueryClient` object. You can then use this object to read data from Google Cloud BigQuery. `[](#__codelineno-3-1)# Cell 1 - Load libraries [](#__codelineno-3-2)import marimo as mo [](#__codelineno-3-3)from google.cloud import bigquery [](#__codelineno-3-4)[](#__codelineno-3-5)# Cell 2 - Load datasets [](#__codelineno-3-6)client = bigquery.Client() [](#__codelineno-3-7)datasets = list(client.list_datasets()) [](#__codelineno-3-8)[](#__codelineno-3-9)# Cell 3 - Select dataset [](#__codelineno-3-10)selected_dataset = mo.ui.dropdown( [](#__codelineno-3-11) label="Select dataset", options=[d.dataset_id for d in datasets] [](#__codelineno-3-12)) [](#__codelineno-3-13)selected_dataset [](#__codelineno-3-14)[](#__codelineno-3-15)# Cell 4 - Load tables [](#__codelineno-3-16)dataset = client.dataset(selected_dataset.value) [](#__codelineno-3-17)tables = list(client.list_tables(dataset)) [](#__codelineno-3-18)selected_table = mo.ui.dropdown( [](#__codelineno-3-19) label="Select table", options=[t.table_id for t in tables] [](#__codelineno-3-20)) [](#__codelineno-3-21)selected_table [](#__codelineno-3-22)[](#__codelineno-3-23)# Cell 5 - Load table data [](#__codelineno-3-24)results = client.list_rows(dataset.table(selected_table.value), max_results=10) [](#__codelineno-3-25)mo.ui.table(results.to_dataframe(), selection=None)` Example[¶](#example "Permanent link") ------------------------------------- Check out our full example using Google Cloud BigQuery [here](https://github.com/marimo-team/marimo/blob/main/examples/cloud/gcp/google_cloud_bigquery.py) Or run it yourself: `[](#__codelineno-4-1)marimo run https://raw.githubusercontent.com/marimo-team/marimo/main/examples/cloud/gcp/google_cloud_bigquery.py` Google Cloud Storage - marimo https://docs.marimo.io/integrations/google_cloud_storage/ Getting Started[¶](#getting-started "Permanent link") ----------------------------------------------------- To use Google Cloud Storage as a data source, you will need to install the `google-cloud-storage` Python package. You can install this package using `pip`: `[](#__codelineno-0-1)pip install google-cloud-storage` Authentication[¶](#authentication "Permanent link") --------------------------------------------------- ### Application Default Credentials (Recommended)[¶](#application-default-credentials-recommended "Permanent link") The easiest way to authenticate with Google Cloud Storage is to use [Application Default Credentials](https://cloud.google.com/docs/authentication/production). If you are running marimo on Google Cloud and your resource has a service account attached, then Application Default Credentials will automatically be used. If you are running marimo locally, you can authenticate with Application Default Credentials by running the following command: `[](#__codelineno-1-1)gcloud auth application-default login` ### Service Account Key File[¶](#service-account-key-file "Permanent link") To authenticate with Google Cloud Storage, you will need to create a service account and download the service account key file. You can create a service account and download the key file by following the instructions [here](https://cloud.google.com/iam/docs/creating-managing-service-account-keys). Once you have downloaded the key file, you can authenticate with Google Cloud Storage by setting the `GOOGLE_APPLICATION_CREDENTIALS` environment variable to the path of the key file: `[](#__codelineno-2-1)export GOOGLE_APPLICATION_CREDENTIALS=/path/to/key/file.json` Reading Data[¶](#reading-data "Permanent link") ----------------------------------------------- To read data from Google Cloud Storage, you will need to create a `StorageClient` object. You can then use this object to read data from Google Cloud Storage. `[](#__codelineno-3-1)# Cell 1 - Load libraries [](#__codelineno-3-2)import marimo as mo [](#__codelineno-3-3)from google.cloud import storage [](#__codelineno-3-4)[](#__codelineno-3-5)# Cell 2 - Load buckets [](#__codelineno-3-6)client = storage.Client() [](#__codelineno-3-7)buckets = client.list_buckets() [](#__codelineno-3-8)[](#__codelineno-3-9)# Cell 3 - Select bucket [](#__codelineno-3-10)selected_bucket = mo.ui.dropdown( [](#__codelineno-3-11) label="Select bucket", options=[b.name for b in buckets] [](#__codelineno-3-12)) [](#__codelineno-3-13)selected_bucket [](#__codelineno-3-14)[](#__codelineno-3-15)# Cell 4 - Load files [](#__codelineno-3-16)files = list(bucket.list_blobs()) [](#__codelineno-3-17)items = [ [](#__codelineno-3-18) { [](#__codelineno-3-19) "Name": f.name, [](#__codelineno-3-20) "Updated": f.updated.strftime("%h %d, %Y"), [](#__codelineno-3-21) "Size": f.size, [](#__codelineno-3-22) } [](#__codelineno-3-23) for f in files [](#__codelineno-3-24)] [](#__codelineno-3-25)file_table = mo.ui.table(items, selection="single") [](#__codelineno-3-26)file_table if items else mo.md("No files found").callout()` Example[¶](#example "Permanent link") ------------------------------------- Check out our full example using Google Cloud Storage [here](https://github.com/marimo-team/marimo/blob/main/examples/cloud/gcp/google_cloud_storage.py) Or run it yourself: `[](#__codelineno-4-1)marimo run https://raw.githubusercontent.com/marimo-team/marimo/main/examples/cloud/gcp/google_cloud_storage.py` MotherDuck - marimo https://docs.marimo.io/integrations/motherduck/ [MotherDuck](https://motherduck.com/) is a cloud-based data warehouse that combines the power of DuckDB with the scalability of the cloud. This guide will help you integrate MotherDuck with marimo. 1\. Connecting to MotherDuck[¶](#1-connecting-to-motherduck "Permanent link") ----------------------------------------------------------------------------- To use MotherDuck as a data source, you'll need to install the `marimo[sql]` Python package. install with pipinstall with uvinstall with conda `[](#__codelineno-0-1)pip install "marimo[sql]"` `[](#__codelineno-2-1)conda install -c conda-forge marimo duckdb polars` To connect to MotherDuck, import `duckdb` and `ATTACH` your MotherDuck database. Using MotherDuck[¶](#using-motherduck "Permanent link") ------------------------------------------------------- ### 1\. Connecting and Database Discovery[¶](#1-connecting-and-database-discovery "Permanent link") SQLPython `[](#__codelineno-3-1)ATTACH IF NOT EXISTS 'md:my_db'` `[](#__codelineno-4-1)import duckdb [](#__codelineno-4-2)# Connect to MotherDuck [](#__codelineno-4-3)duckdb.sql("ATTACH IF NOT EXISTS 'md:my_db'")` You will be prompted to authenticate with MotherDuck when you run the above cell. This will open a browser window where you can log in and authorize your marimo notebook to access your MotherDuck database. In order to avoid being prompted each time you open a notebook, you can set the `motherduck_token` environment variable: `[](#__codelineno-5-1)export motherduck_token="your_token" [](#__codelineno-5-2)marimo edit` Once connected, your MotherDuck tables are automatically discovered in the Datasources Panel: Browse your MotherDuck databases ### 2\. Writing SQL Queries[¶](#2-writing-sql-queries "Permanent link") You can query your MotherDuck tables using SQL cells in marimo. Here's an example of how to query a table and display the results using marimo: Query a MotherDuck table marimo's reactive execution model extends into SQL queries, so changes to your SQL will automatically trigger downstream computations for dependent cells (or optionally mark cells as stale for expensive computations). ### 3\. Mixing SQL and Python[¶](#3-mixing-sql-and-python "Permanent link") MotherDuck allows you to seamlessly mix SQL queries with Python code, enabling powerful data manipulation and analysis. Here's an example: Mixing SQL and Python This example demonstrates how you can use SQL to query your data, then use Python and marimo to further analyze and visualize the results. Example Notebook[¶](#example-notebook "Permanent link") ------------------------------------------------------- For a full example of using MotherDuck with marimo, check out our [MotherDuck example notebook](https://github.com/marimo-team/marimo/blob/main/examples/sql/connect_to_motherduck.py). `[](#__codelineno-6-1)marimo edit https://github.com/marimo-team/marimo/blob/main/examples/sql/connect_to_motherduck.py` Google Sheets - marimo https://docs.marimo.io/integrations/google_sheets/ Getting Started[¶](#getting-started "Permanent link") ----------------------------------------------------- To use Google Sheets as a data source, you will need to install the `gspread` and `oauth2client` Python packages. You can install this package using `pip`: `[](#__codelineno-0-1)pip install gspread oauth2client` Authentication[¶](#authentication "Permanent link") --------------------------------------------------- ### Application Default Credentials (Recommended)[¶](#application-default-credentials-recommended "Permanent link") The easiest way to authenticate with Google Sheets is to use [Application Default Credentials](https://cloud.google.com/docs/authentication/production). If you are running marimo on Google Cloud and your resource has a service account attached, then Application Default Credentials will automatically be used. If you are running marimo locally, you can authenticate with Application Default Credentials by running the following command: `[](#__codelineno-1-1)gcloud auth application-default login` ### Service Account Key File[¶](#service-account-key-file "Permanent link") To authenticate with Google Sheets, you will need to create a service account and download the service account key file. You can create a service account and download the key file by following the instructions [here](https://cloud.google.com/iam/docs/creating-managing-service-account-keys). Once you have downloaded the key file, you can authenticate with Google Sheets by setting the `GOOGLE_APPLICATION_CREDENTIALS` environment variable to the path of the key file: `[](#__codelineno-2-1)export GOOGLE_APPLICATION_CREDENTIALS=/path/to/key/file.json` Reading Data[¶](#reading-data "Permanent link") ----------------------------------------------- To read data from Google Sheets, you will need to authenticate and create a `gspread.Client`. You can then use this object to read data from Google Sheets. `[](#__codelineno-3-1)# Cell 1 - Load libraries [](#__codelineno-3-2)import marimo as mo [](#__codelineno-3-3)import pandas as pd [](#__codelineno-3-4)import os [](#__codelineno-3-5)import gspread [](#__codelineno-3-6)from oauth2client.service_account import ServiceAccountCredentials [](#__codelineno-3-7)[](#__codelineno-3-8)# Authenticate with Google Sheets [](#__codelineno-3-9)scope = [ [](#__codelineno-3-10) "https://spreadsheets.google.com/feeds", [](#__codelineno-3-11) "https://www.googleapis.com/auth/drive", [](#__codelineno-3-12)] [](#__codelineno-3-13)credentials = ServiceAccountCredentials.from_json_keyfile_name( [](#__codelineno-3-14) os.environ["GOOGLE_APPLICATION_CREDENTIALS"], scope [](#__codelineno-3-15)) [](#__codelineno-3-16)gc = gspread.authorize(credentials) [](#__codelineno-3-17)[](#__codelineno-3-18)# Cell 2 - Load the sheet [](#__codelineno-3-19)wks = gc.open("marimo").sheet1 [](#__codelineno-3-20)mo.ui.table(pd.DataFrame(wks.get_all_records()))` Example[¶](#example "Permanent link") ------------------------------------- Check out our full example using Google Sheets [here](https://github.com/marimo-team/marimo/blob/main/examples/cloud/gcp/google_sheets.py) Or run it yourself: `[](#__codelineno-4-1)marimo run https://raw.githubusercontent.com/marimo-team/marimo/main/examples/cloud/gcp/google_sheets.py` FAQ - marimo https://docs.marimo.io/faq.html#faq-jupyter Choosing marimo[¶](#choosing-marimo "Permanent link") ----------------------------------------------------- ### How is marimo different from Jupyter?[¶](#how-is-marimo-different-from-jupyter "Permanent link") marimo is a reinvention of the Python notebook as a reproducible, interactive, and shareable Python program that can be executed as scripts or deployed as interactive web apps. **Consistent state.** In marimo, your notebook code, outputs, and program state are guaranteed to be consistent. Run a cell and marimo reacts by automatically running the cells that reference its variables. Delete a cell and marimo scrubs its variables from program memory, eliminating hidden state. **Built-in interactivity.** marimo also comes with [UI elements](https://docs.marimo.io/guides/interactivity/) like sliders, a dataframe transformer, and interactive plots that are automatically synchronized with Python. Interact with an element and the cells that use it are automatically re-run with its latest value. **Pure Python programs.** Unlike Jupyter notebooks, marimo notebooks are stored as pure Python files that can be executed as scripts, deployed as interactive web apps, and versioned easily with Git. ### What problems does marimo solve?[¶](#what-problems-does-marimo-solve "Permanent link") marimo solves problems in reproducibility, maintainability, interactivity, reusability, and shareability of notebooks. **Reproducibility.** In Jupyter notebooks, the code you see doesn't necessarily match the outputs on the page or the program state. If you delete a cell, its variables stay in memory, which other cells may still reference; users can execute cells in arbitrary order. This leads to widespread reproducibility issues. [One study](https://blog.jetbrains.com/datalore/2020/12/17/we-downloaded-10-000-000-jupyter-notebooks-from-github-this-is-what-we-learned/#consistency-of-notebooks) analyzed 10 million Jupyter notebooks and found that 36% of them weren't reproducible. In contrast, marimo guarantees that your code, outputs, and program state are consistent, eliminating hidden state and making your notebook reproducible. marimo achieves this by intelligently analyzing your code and understanding the relationships between cells, and automatically re-running cells as needed. In addition, marimo notebooks can serialize package requirements inline; marimo runs these "sandboxed" notebooks in temporary virtual environments, making them [reproducible down to the packages](https://docs.marimo.io/guides/editor_features/package_management/). **Maintainability.** marimo notebooks are stored as pure Python programs (`.py` files). This lets you version them with Git; in contrast, Jupyter notebooks are stored as JSON and require extra steps to version. **Interactivity.** marimo notebooks come with [UI elements](https://docs.marimo.io/guides/interactivity/) that are automatically synchronized with Python (like sliders, dropdowns); _eg_, scrub a slider and all cells that reference it are automatically re-run with the new value. This is difficult to get working in Jupyter notebooks. **Reusability.** marimo notebooks can be executed as Python scripts from the command-line (since they're stored as `.py` files). In contrast, this requires extra steps to do for Jupyter, such as copying and pasting the code out or using external frameworks. We also let you import symbols (functions, classes) defined in a marimo notebook into other Python programs/notebooks, something you can't easily do with Jupyter. **Shareability.** Every marimo notebook can double as an interactive web app, complete with UI elements, which you can serve using the `marimo run` command. This isn't possible in Jupyter without substantial extra effort. _To learn more about problems with traditional notebooks, see these references [\[1\]](https://austinhenley.com/pubs/Chattopadhyay2020CHI_NotebookPainpoints.pdf) [\[2\]](https://www.youtube.com/watch?v=7jiPeIFXb6U&t=1s)._ ### How is `marimo.ui` different from Jupyter widgets?[¶](#how-is-marimoui-different-from-jupyter-widgets "Permanent link") Unlike Jupyter widgets, marimo's interactive elements are automatically synchronized with the Python kernel: no callbacks, no observers, no manually re-running cells. Using marimo[¶](#using-marimo "Permanent link") ----------------------------------------------- ### Is marimo a notebook or a library?[¶](#is-marimo-a-notebook-or-a-library "Permanent link") marimo is both a notebook and a library. * Create _marimo notebooks_ with the editor that opens in your browser when you run `marimo edit`. * Use the _marimo library_ (`import marimo as mo`) in marimo notebooks. Write markdown with `mo.md(...)`, create stateful interactive elements with `mo.ui` (`mo.ui.slider(...)`), and more. See the docs for an [API reference](https://docs.marimo.io/api/). ### What's the difference between a marimo notebook and a marimo app?[¶](#whats-the-difference-between-a-marimo-notebook-and-a-marimo-app "Permanent link") marimo programs are notebooks, apps, or both, depending on how you use them. There are two ways to interact with a marimo program: 1. open it as a computational _notebook_ with `marimo edit` 2. run it as an interactive _app_ with `marimo run` All marimo programs start as notebooks, since they are created with `marimo edit`. Because marimo notebooks are reactive and have built-in interactive elements, many can easily be made into useful and beautiful apps by simply hiding the notebook code: this is what `marimo run` does. Not every notebook needs to be run as an app — marimo notebooks are useful in and of themselves for rapidly exploring data and doing reproducible science. And not every app is improved by interacting with the notebook. In some settings, such as collaborative research, education, and technical presentations, going back and forth between the notebook view and app view (which you can do from `marimo edit`) can be useful! ### How does marimo know what cells to run?[¶](#how-does-marimo-know-what-cells-to-run "Permanent link") marimo reads each cell once to determine what global names it defines and what global names it reads. When a cell is run, marimo runs all other cells that read any of the global names it defines. A global name can refer to a variable, class, function, or import. In other words, marimo uses _static analysis_ to make a dataflow graph out of your cells. Each cell is a node in the graph across which global variables "flow". Whenever a cell is run, either because you changed its code or interacted with a UI element it reads, all its descendants run in turn. ### Does marimo slow my code down?[¶](#does-marimo-slow-my-code-down "Permanent link") No, marimo doesn't slow your code down. marimo determines the dependencies among cells by reading your code, not running or tracing it, so there's zero runtime overhead. ### How do I prevent automatic execution from running expensive cells?[¶](#how-do-i-prevent-automatic-execution-from-running-expensive-cells "Permanent link") Reactive (automatic) execution ensures your code and outputs are always in sync, improving reproducibility by eliminating hidden state and out-of-order execution; marimo also takes care to run only the minimal set of cells needed to keep your notebook up to date. But when some cells take a long time to run, it's understandable to be concerned that automatic execution will kick off expensive cells before you're ready to run them. _Here are some tips to avoid accidental execution of expensive cells:_ * [Disable expensive cells](https://docs.marimo.io/guides/reactivity/#disabling-cells). When a cell is disabled, it and its descendants are blocked from running. * Wrap UI elements in a [form](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form"). * Use [`mo.stop`](https://docs.marimo.io/api/control_flow/#marimo.stop " marimo.stop") to conditionally stop execution of a cell and its descendants. * Decorate functions with marimo's [`mo.cache`](https://docs.marimo.io/api/caching/#marimo.cache " marimo.cache") to cache expensive intermediate computations. * Use [`mo.persistent_cache`](https://docs.marimo.io/api/caching/#marimo.persistent_cache " marimo.persistent_cache") to cache variables to disk; on re-run, marimo will read values from disk instead of recalculating them as long as the cell is not stale. * Disable automatic execution in the [runtime configuration](https://docs.marimo.io/guides/configuration/runtime_configuration/). ### How do I disable automatic execution?[¶](#how-do-i-disable-automatic-execution "Permanent link") You can disable automatic execution through the notebook runtime settings; see the [guide on runtime configuration](https://docs.marimo.io/guides/configuration/runtime_configuration/). When automatic execution is disabled, marimo still gives you guarantees on your notebook state and automatically marks cells as stale when appropriate. ### How do I use sliders and other interactive elements?[¶](#how-do-i-use-sliders-and-other-interactive-elements "Permanent link") Interactive UI elements like sliders are available in `marimo.ui`. * Assign the UI element to a global variable (`slider = mo.ui.slider(0, 100)`) * Include it in the last expression of a cell to display it (`slider` or `mo.md(f"Choose a value: {slider}")`) * Read its current value in another cell via its `value` attribute (`slider.value`) _When a UI element bound to a global variable is interacted with, all cells referencing the global variable are run automatically_. If you have many UI elements or don't know the elements you'll create until runtime, use `marimo.ui.array` and `marimo.ui.dictionary` to create UI elements that wrap other UI elements (`sliders = mo.ui.array([slider(1, 100) for _ in range(n_sliders)])`). All this and more is explained in the UI tutorial. Run it with at the command line. ### How do I add a submit button to UI elements?[¶](#how-do-i-add-a-submit-button-to-ui-elements "Permanent link") Use the `form` method to add a submit button to a UI element. For example, `[](#__codelineno-1-1)form = marimo.ui.text_area().form()` When wrapped in a form, the text area's value will only be sent to Python when you click the submit button. Access the last submitted value of the text area with `form.value`. ### How do I write markdown?[¶](#how-do-i-write-markdown "Permanent link") Import `marimo` (as `mo`) in a notebook, and use the `mo.md` function. Learn more in the [outputs guide](https://docs.marimo.io/guides/outputs/#markdown) or by running `marimo tutorial markdown`. ### How do I display plots?[¶](#how-do-i-display-plots "Permanent link") Include plots in the last expression of a cell to display them, just like all other outputs. If you're using matplotlib, you can display the `Figure` object (get the current figure with `plt.gcf()`). For examples, run the plots tutorial: Also see the [plotting API reference](https://docs.marimo.io/api/plotting/). ### How do I prevent matplotlib plots from being cut off?[¶](#how-do-i-prevent-matplotlib-plots-from-being-cut-off "Permanent link") If your legend or axes labels are cut off, try calling `plt.tight_layout()` before outputting your plot: `[](#__codelineno-3-1)import matplotlib.pyplot as plt [](#__codelineno-3-2)[](#__codelineno-3-3)plt.plot([-8, 8]) [](#__codelineno-3-4)plt.ylabel("my variable") [](#__codelineno-3-5)plt.tight_layout() [](#__codelineno-3-6)plt.gca()` ### How do I display interactive matplotlib plots?[¶](#how-do-i-display-interactive-matplotlib-plots "Permanent link") Use [`marimo.mpl.interactive`](https://docs.marimo.io/api/plotting/#marimo.mpl.interactive " marimo.mpl.interactive"). `[](#__codelineno-4-1)fig, ax = plt.subplots() [](#__codelineno-4-2)ax.plot([1, 2]) [](#__codelineno-4-3)mo.mpl.interactive(ax)` ### How do I display objects in rows and columns?[¶](#how-do-i-display-objects-in-rows-and-columns "Permanent link") Use `marimo.hstack` and `marimo.vstack`. See the layout tutorial for details: ### How do I show cell code in the app view?[¶](#how-do-i-show-cell-code-in-the-app-view "Permanent link") Use [`mo.show_code`](https://docs.marimo.io/api/outputs/#marimo.show_code " marimo.show_code"). ### How do I create an output with a dynamic number of UI elements?[¶](#how-do-i-create-an-output-with-a-dynamic-number-of-ui-elements "Permanent link") Use [`mo.ui.array`](https://docs.marimo.io/api/inputs/array/#marimo.ui.array " marimo.ui.array"), [`mo.ui.dictionary`](https://docs.marimo.io/api/inputs/dictionary/#marimo.ui.dictionary " marimo.ui.dictionary"), or [`mo.ui.batch`](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch") to create a UI element that wraps a dynamic number of other UI elements. If you need custom formatting, use [`mo.ui.batch`](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch"), otherwise use [`mo.ui.array`](https://docs.marimo.io/api/inputs/array/#marimo.ui.array " marimo.ui.array") or [`mo.ui.dictionary`](https://docs.marimo.io/api/inputs/dictionary/#marimo.ui.dictionary " marimo.ui.dictionary"). For usage examples, see the [recipes for grouping UI elements together](https://docs.marimo.io/recipes/#grouping-ui-elements-together). ### How do I let users interrupt a progress bar iteration?[¶](#how-do-i-let-users-interrupt-a-progress-bar-iteration "Permanent link") To create an interruptible progress bar, run the progress bar in its own thread, and create a button that on change signals to the thread that it should exit. Example: `[](#__codelineno-6-1)import marimo [](#__codelineno-6-2)[](#__codelineno-6-3)__generated_with = "0.20.1" [](#__codelineno-6-4)app = marimo.App() [](#__codelineno-6-5) [](#__codelineno-6-6)[](#__codelineno-6-7)@app.cell [](#__codelineno-6-8)def _(): [](#__codelineno-6-9) import marimo as mo [](#__codelineno-6-10) import time [](#__codelineno-6-11) from threading import Event [](#__codelineno-6-12) return Event, mo, time [](#__codelineno-6-13) [](#__codelineno-6-14)[](#__codelineno-6-15)@app.cell [](#__codelineno-6-16)def _(Event): [](#__codelineno-6-17) cancelled = Event() [](#__codelineno-6-18) return (cancelled,) [](#__codelineno-6-19) [](#__codelineno-6-20)[](#__codelineno-6-21)@app.cell [](#__codelineno-6-22)def _(cancelled, mo): [](#__codelineno-6-23) cancel = mo.ui.button( [](#__codelineno-6-24) label="Interrupt the progress bar", on_change=lambda _: cancelled.set() [](#__codelineno-6-25) ) [](#__codelineno-6-26) cancel [](#__codelineno-6-27) return [](#__codelineno-6-28) [](#__codelineno-6-29)[](#__codelineno-6-30)@app.cell [](#__codelineno-6-31)def _(cancelled, mo, time): [](#__codelineno-6-32) def progress(total): [](#__codelineno-6-33) with mo.status.progress_bar(total=10) as pbar: [](#__codelineno-6-34) for _ in range(10): [](#__codelineno-6-35) if cancelled.is_set(): [](#__codelineno-6-36) pbar.update( [](#__codelineno-6-37) increment=0, subtitle="The user cancelled the iteration" [](#__codelineno-6-38) ) [](#__codelineno-6-39) break [](#__codelineno-6-40) # Sleep... or anything else that releases GIL [](#__codelineno-6-41) time.sleep(0.5) [](#__codelineno-6-42) pbar.update() [](#__codelineno-6-43) [](#__codelineno-6-44) return (progress,) [](#__codelineno-6-45) [](#__codelineno-6-46)[](#__codelineno-6-47)@app.cell [](#__codelineno-6-48)def _(mo, progress): [](#__codelineno-6-49) mo.Thread(target=progress, args=(10,)).start() [](#__codelineno-6-50) return [](#__codelineno-6-51) [](#__codelineno-6-52)[](#__codelineno-6-53)if __name__ == "__main__": [](#__codelineno-6-54) app.run()` ### How do I restart a notebook?[¶](#how-do-i-restart-a-notebook "Permanent link") To clear all program memory and restart the notebook from scratch, open the notebook menu in the top right and click "Restart kernel". ### How do I reload modules?[¶](#how-do-i-reload-modules "Permanent link") Enable automatic reloading of modules via the runtime settings in your marimo installation's user configuration. (Click the "gear" icon in the top right of a marimo notebook). When enabled, marimo will automatically hot-reload modified modules before executing a cell. ### Why aren't my `on_change`/`on_click` handlers being called?[¶](#why-arent-my-on_changeon_click-handlers-being-called "Permanent link") A UI Element's `on_change` (or for buttons, `on_click`) handlers are only called if the element is bound to a global variable. For example, this won't work `[](#__codelineno-7-1)mo.vstack([mo.ui.button(on_change=lambda _: print("I was called")) for _ in range(10)])` In such cases (when you want to output a dynamic number of UI elements), you need to use [`mo.ui.array`](https://docs.marimo.io/api/inputs/array/#marimo.ui.array " marimo.ui.array"), [`mo.ui.dictionary`](https://docs.marimo.io/api/inputs/dictionary/#marimo.ui.dictionary " marimo.ui.dictionary"), or [`mo.ui.batch`](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch"). See the [recipes for grouping UI elements together](https://docs.marimo.io/recipes/#grouping-ui-elements-together) for example code. ### Why are my `on_change` handlers in an array all referencing the last element?[¶](#why-are-my-on_change-handlers-in-an-array-all-referencing-the-last-element "Permanent link") **Don't do this**: In the below snippet, every `on_change` will print `9`!. `[](#__codelineno-8-1)array = mo.ui.array( [](#__codelineno-8-2) [mo.ui.button(on_change=lambda value: print(i)) for i in range(10) [](#__codelineno-8-3)])` **Instead, do this**: Explicitly bind `i` to the current loop value: `[](#__codelineno-9-1)array = mo.ui.array( [](#__codelineno-9-2) [mo.ui.button(on_change=lambda value, i=i: print(i)) for i in range(10)] [](#__codelineno-9-3)) [](#__codelineno-9-4)array` This is necessary because [in Python, closures are late-binding](https://docs.python-guide.org/writing/gotchas/#late-binding-closures). ### Why aren't my SQL brackets working?[¶](#why-arent-my-sql-brackets-working "Permanent link") Our "SQL" cells are really just Python under the hood to keep notebooks as pure Python scripts. By default, we use `f-strings` for SQL strings, which allows for parameterized SQL like `SELECT * from table where value < {min}`. To escape real `{` / `}` that you don't want parameterized, use double `\{\{...\}\}`: `[](#__codelineno-10-1)SELECT unnest([\{\{'a': 42, 'b': 84\}\}, \{\{'a': 100, 'b': NULL\}\}]);` ### How does marimo treat type annotations?[¶](#how-does-marimo-treat-type-annotations "Permanent link") Type annotations are registered as references of a cell, unless they are explicitly written as strings. This helps ensure correctness of code that depends on type annotations at runtime (_e.g._, Pydantic), while still providing a way to omit annotations from affecting dataflow graph. For example, in `A` is treated as a reference, used in determining the dataflow graph, but in `A` isn't made a reference. For Python 3.12+, marimo additionally implements annotation scoping. ### How do I use dotenv?[¶](#how-do-i-use-dotenv "Permanent link") The package `dotenv`'s `loadenv()` function does not work out-of-the box in marimo. Instead, use `dotenv.load_dotenv(dotenv.find_dotenv(usecwd=True))`. ### What packages can I use?[¶](#what-packages-can-i-use "Permanent link") You can use any Python package. marimo cells run arbitrary Python code. ### How do I use marimo on a remote server?[¶](#how-do-i-use-marimo-on-a-remote-server "Permanent link") > We recorded a video tutorial on how to use marimo on a remote server. Check it out [here](https://youtu.be/pam9Hw8rbaA). Use SSH port-forwarding to run marimo on a remote server and connect to it from a browser on your local machine. Make sure to pass the `--headless` flag when starting marimo on remote; on the remote machine, we also recommend using a port other than marimo's default port, such as 8080: _On the remote machine, run:_ `[](#__codelineno-13-1)marimo edit --headless --port 8080` or, if you want to set a custom host: `[](#__codelineno-14-1)marimo edit --headless --host 0.0.0.0 --port 8080` _On local, run:_ `[](#__codelineno-15-1)ssh -N -L 3718:127.0.0.1:8080 REMOTE_USER@REMOTE_HOST` Then open `localhost:3718` in your browser. ### How do I make marimo accessible on all network interfaces?[¶](#how-do-i-make-marimo-accessible-on-all-network-interfaces "Permanent link") Use `--host 0.0.0.0` with `marimo edit`, `marimo run`, or `marimo tutorial`: `[](#__codelineno-16-1)marimo edit --host 0.0.0.0` ### How do I use marimo behind JupyterHub?[¶](#how-do-i-use-marimo-behind-jupyterhub "Permanent link") JupyterHub can be configured to launch marimo using the [`marimo-jupyter-extension`](https://github.com/marimo-team/marimo-jupyter-extension). ### How do I use marimo with JupyterBook?[¶](#how-do-i-use-marimo-with-jupyterbook "Permanent link") [JupyterBook](https://jupyterbook.org/en/stable/intro.html) makes it easy to create static websites with markdown and Jupyter notebooks. To include a marimo notebook in a JupyterBook, you can either export your notebook to an `ipynb` file, or export to `HTML`: 1. export to ipynb: `marimo export ipynb my_notebook.py -o my_notebook.ipynb --include-outputs` 2. export to HTML: `marimo export html my_notebook.py -o my_notebook.html` ### How do I deploy apps?[¶](#how-do-i-deploy-apps "Permanent link") Use the marimo CLI's `run` command to serve a notebook as an app: If you are running marimo inside a Docker container, you may want to run under a different host and port: `[](#__codelineno-18-1)marimo run notebook.py --host 0.0.0.0 --port 8080` ### Is marimo free?[¶](#is-marimo-free "Permanent link") Yes! Key Concepts - marimo https://docs.marimo.io/getting_started/key_concepts This page covers marimo's key concepts: * marimo lets you rapidly experiment with data using Python, SQL, and interactive elements in a reproducible **notebook environment**. * Unlike Jupyter notebooks, marimo notebooks are reusable software artifacts. marimo notebooks can be shared as as **interactive web apps** and executed as **Python scripts**. Editing notebooks[¶](#editing-notebooks "Permanent link") --------------------------------------------------------- marimo notebooks are **reactive**: they automatically react to your code changes and UI interactions and keep your notebook up-to-date, not unlike a spreadsheet. This makes your notebooks reproducible, [eliminating hidden state](https://docs.marimo.io/faq/#faq-problems); it's also what enables marimo notebooks to double as apps and Python scripts. Working with expensive notebooks If you don't want cells to run automatically, the [runtime can be configured](https://docs.marimo.io/guides/configuration/runtime_configuration/) to be lazy, only running cells when you ask for them to be run and marking affected cells as stale. **See our guide on working with [expensive notebooks](https://docs.marimo.io/guides/expensive_notebooks/) for more tips.** **Create your first notebook.** After [installing marimo](https://docs.marimo.io/installation/), create your first notebook with `[](#__codelineno-0-1)marimo edit my_notebook.py` at the command-line. **The marimo library**. We recommend starting each marimo notebook with a cell containing a single line of code, The marimo library lets you use interactive UI elements, layout elements, dynamic markdown, and more in your marimo notebooks. ### How marimo executes cells[¶](#how-marimo-executes-cells "Permanent link") A marimo notebook is made of small blocks of Python code called **cells**. _When you run a cell, marimo automatically runs all cells that read any global variables defined by that cell._ This is reactive execution. **Execution order.** The order of cells on the page has no bearing on the order cells are executed in: execution order is determined by the variables cells define and the variables they read. You have full freedom over how to organize your code and tell your stories: move helper functions and other "appendices" to the bottom of your notebook, or put cells with important outputs at the top. **No hidden state.** marimo notebooks have no hidden state because the program state is automatically synchronized with your code changes and UI interactions. And if you delete a cell, marimo automatically deletes that cell's variables, preventing painful bugs that arise in traditional notebooks. **No magical syntax.** There's no magical syntax or API required to opt-in to reactivity: cells are Python and _only Python_. Behind-the-scenes, marimo statically analyzes each cell's code just once, creating a directed acyclic graph based on the global names each cell defines and reads. This is how data flows in a marimo notebook. Minimize variable mutation. marimo's understanding of your code is based on variable definitions and references; marimo does not track mutations to objects at runtime. For this reason, if you need to mutate a variable (such as adding a new column to a dataframe), you should perform the mutation in the same cell as the one that defines it. Learn more in our [reactivity guide](https://docs.marimo.io/guides/reactivity/#reactivity-mutations). For more on reactive execution, open the dataflow tutorial or read the [reactivity guide](https://docs.marimo.io/guides/reactivity/). To visualize and understand how data flows through your notebook, check out our [dataflow tools](https://docs.marimo.io/guides/editor_features/dataflow/). ### Visualizing outputs[¶](#visualizing-outputs "Permanent link") marimo visualizes the last expression of each cell as its **output**. Outputs can be any Python value, including markdown and interactive elements created with the marimo library, (_e.g._, [`mo.md`](https://docs.marimo.io/api/markdown/#marimo.md " marimo.md"), [`mo.ui.slider`](https://docs.marimo.io/api/inputs/slider/#marimo.ui.slider " marimo.ui.slider")). You can even interpolate Python values into markdown (using `mo.md(f"...")`) and other marimo elements to build rich composite outputs: > Thanks to reactive execution, running a cell refreshes all the relevant outputs in your notebook. The marimo library also comes with elements for laying out outputs, including [`mo.hstack`](https://docs.marimo.io/api/layouts/stacks/#marimo.hstack " marimo.hstack"), [`mo.vstack`](https://docs.marimo.io/api/layouts/stacks/#marimo.vstack " marimo.vstack"), [`mo.accordion`](https://docs.marimo.io/api/layouts/accordion/#marimo.accordion " marimo.accordion"), [`mo.ui.tabs`](https://docs.marimo.io/api/inputs/tabs/#marimo.ui.tabs " marimo.ui.tabs"), [`mo.sidebar`](https://docs.marimo.io/api/layouts/sidebar/#marimo.sidebar " marimo.sidebar"), [`mo.nav_menu`](https://docs.marimo.io/api/inputs/nav_menu/#marimo.nav_menu " marimo.nav_menu"), [`mo.ui.table`](https://docs.marimo.io/api/inputs/table/#marimo.ui.table " marimo.ui.table"), and [many more](https://docs.marimo.io/api/layouts/). For more on outputs, try these tutorials: `[](#__codelineno-3-1)marimo tutorial markdown [](#__codelineno-3-2)marimo tutorial plots [](#__codelineno-3-3)marimo tutorial layout` or read the [visualizing outputs guide](https://docs.marimo.io/guides/outputs/). ### Creating interactive elements[¶](#creating-interactive-elements "Permanent link") The marimo library comes with many interactive stateful elements in [`marimo.ui`](https://docs.marimo.io/api/inputs/), including simple ones like sliders, dropdowns, text fields, and file upload areas, as well as composite ones like forms, arrays, and dictionaries that can wrap other UI elements. **Using UI elements.** To use a UI element, create it with `mo.ui` and **assign it to a global variable.** When you interact with a UI element in your browser (_e.g._, sliding a slider), _marimo sends the new value back to Python and reactively runs all cells that use the element_, which you can access via its `value` attribute. > **This combination of interactivity and reactivity is very powerful**: use it to make your data tangible during exploration and to build all kinds of tools and apps. _marimo can only synchronize UI elements that are assigned to global variables._ Use composite elements like [`mo.ui.array`](https://docs.marimo.io/api/inputs/array/#marimo.ui.array " marimo.ui.array") and [`mo.ui.dictionary`](https://docs.marimo.io/api/inputs/dictionary/#marimo.ui.dictionary " marimo.ui.dictionary") if the set of UI elements is not known until runtime. Using buttons to execute cells Use [`mo.ui.run_button`](https://docs.marimo.io/api/inputs/run_button/#marimo.ui.run_button " marimo.ui.run_button") to create a button that triggers computation when clicked; see our recipes for [an example](https://docs.marimo.io/recipes/#create-a-button-that-triggers-computation-when-clicked). For more on interactive elements, run the UI tutorial or read the [interactivity guide](https://docs.marimo.io/guides/interactivity/). ### Querying dataframes and databases with SQL[¶](#querying-dataframes-and-databases-with-sql "Permanent link") marimo has built-in support for SQL: you can query Python dataframes, databases, CSVs, Google Sheets, or anything else. After executing your query, marimo returns the result to you as a dataframe, making it seamless to go back and forth between SQL and Python. Query a dataframe using SQL! To create a SQL cell, click on the SQL button that appears at the bottom of the cell array, or right click the create cell button next to a cell. Today, SQL in marimo is executed using [duckdb](https://duckdb.org/docs/). To learn more, run the SQL tutorial or read the [SQL guide](https://docs.marimo.io/guides/working_with_data/sql/). Running notebooks as applications[¶](#running-notebooks-as-applications "Permanent link") ----------------------------------------------------------------------------------------- You can use marimo as a notebook, similar to how you might use Jupyter. But you can also do more: because marimo notebooks are reactive and can include interactive elements, hiding notebook code gives you a simple web app! You can run your notebook as a read-only web app from the command-line: `[](#__codelineno-6-1)marimo run my_notebook.py` The default renderer just hides the notebook code and concatenates outputs vertically. But marimo also supports [other layouts](https://docs.marimo.io/guides/apps/), such as slides and grid. Running notebooks as scripts[¶](#running-notebooks-as-scripts "Permanent link") ------------------------------------------------------------------------------- Because marimo notebooks are stored as pure Python files, each notebook can be executed as a script from the command-line: You can also [pass command-line arguments](https://docs.marimo.io/guides/scripts/) to scripts. Plotting - marimo https://docs.marimo.io/guides/working_with_data/plotting marimo supports most major plotting libraries, including Matplotlib, Seaborn, Plotly, Altair, and HoloViews. Just import your plotting library of choice and use it as you normally would. For matplotlib, Altair, and Plotly plots, marimo does something special: wrap your plot in [`mo.ui.matplotlib`](https://docs.marimo.io/api/plotting/#marimo.ui.matplotlib " marimo.ui.matplotlib"), [`mo.ui.altair_chart`](https://docs.marimo.io/api/plotting/#marimo.ui.altair_chart " marimo.ui.altair_chart") or [`mo.ui.plotly`](https://docs.marimo.io/api/plotting/#marimo.ui.plotly " marimo.ui.plotly"), then select and filter with your mouse — marimo automatically sends the selected data back to Python! > For a video overview of reactive plots, check out our [YouTube tutorial](https://youtu.be/KFXsm1wr408). Reactive plots! ⚡[¶](#reactive-plots "Permanent link") ------------------------------------------------------ Requirements Reactive plots currently require matplotlib, Altair, or Plotly. Matplotlib supports box and lasso selections (best suited for scatter plots); selections in Plotly are limited to scatter/scattergl plots, bar charts, histograms, heatmaps, treemaps, and sunburst charts; Altair supports a larger class of plots for selections. ### matplotlib[¶](#matplotlib "Permanent link") Use [`mo.ui.matplotlib`](https://docs.marimo.io/api/plotting/#marimo.ui.matplotlib " marimo.ui.matplotlib") to make matplotlib plots **reactive**: select data on the frontend, then use the selection to filter your data in Python. Two selection modes are supported: * **Box selection** — click and drag to draw a rectangular region. * **Lasso selection** — hold Shift and drag to draw a freehand polygon. After selecting, use `fig.value.get_mask(x, y)` to get a boolean mask of the points inside the selection. When nothing is selected, `fig.value` is falsy and `get_mask()` returns an all-`False` array. #### Example[¶](#example "Permanent link") codelive example `[](#__codelineno-0-1)import matplotlib.pyplot as plt [](#__codelineno-0-2)import marimo as mo [](#__codelineno-0-3)import numpy as np [](#__codelineno-0-4)[](#__codelineno-0-5)x = np.random.randn(500) [](#__codelineno-0-6)y = np.random.randn(500) [](#__codelineno-0-7)plt.scatter(x, y) [](#__codelineno-0-8)# Wrap the Axes in mo.ui.matplotlib to make them reactive ⚡ [](#__codelineno-0-9)ax = mo.ui.matplotlib(plt.gca()) [](#__codelineno-0-10)ax` `[](#__codelineno-1-1)# In another cell — filter your data using the selection [](#__codelineno-1-2)mask = ax.value.get_mask(x, y) [](#__codelineno-1-3)selected_x, selected_y = x[mask], y[mask]` #### Debouncing[¶](#debouncing "Permanent link") By default, the selection streams to Python as you drag. For expensive downstream computations or very large datasets, pass `debounce=True` so the value is only sent on mouse-up: `[](#__codelineno-3-1)ax = mo.ui.matplotlib(plt.gca(), debounce=True)` #### Selection types[¶](#selection-types "Permanent link") `ax.value` is one of three types: | Type | When | Attributes | | --- | --- | --- | | `EmptySelection` | Nothing selected (falsy) | — | | `BoxSelection` | Box drag | `x_min`, `x_max`, `y_min`, `y_max` | | `LassoSelection` | Shift+drag | `vertices` (tuple of `(x, y)` pairs) | All three have a `get_mask(x, y)` method that returns a boolean NumPy array, so you can always write: `[](#__codelineno-4-1)mask = ax.value.get_mask(x, y)` ### Altair[¶](#altair "Permanent link") Use [`mo.ui.altair_chart`](https://docs.marimo.io/api/plotting/#marimo.ui.altair_chart " marimo.ui.altair_chart") to easily create interactive, selectable plots: _selections you make on the frontend are automatically made available as Pandas dataframes in Python._ Wrap an Altair chart in [`mo.ui.altair_chart`](https://docs.marimo.io/api/plotting/#marimo.ui.altair_chart " marimo.ui.altair_chart") to make it **reactive**: select data on the frontend, access it via the chart's `value` attribute (`chart.value`). #### Disabling automatic selection[¶](#disabling-automatic-selection "Permanent link") marimo automatically adds a default selection based on the mark type, however, you may want to customize the selection behavior of your Altair chart. You can do this by setting `chart_selection` and `legend_selection` to `False`, and using `.add_params` directly on your Altair chart. `[](#__codelineno-6-1)# Create an interval selection [](#__codelineno-6-2)brush = alt.selection_interval(encodings=["x"]) [](#__codelineno-6-3)[](#__codelineno-6-4)_chart = ( [](#__codelineno-6-5) alt.Chart(traces, height=150) [](#__codelineno-6-6) .mark_line() [](#__codelineno-6-7) .encode(x="index:Q", y="value:Q", color="traces:N") [](#__codelineno-6-8) .add_params(brush) # add the selection to the chart [](#__codelineno-6-9)) [](#__codelineno-6-10)[](#__codelineno-6-11)chart = mo.ui.altair_chart( [](#__codelineno-6-12) _chart, [](#__codelineno-6-13) # disable automatic selection [](#__codelineno-6-14) chart_selection=False, [](#__codelineno-6-15) legend_selection=False [](#__codelineno-6-16)) [](#__codelineno-6-17)chart # You can now access chart.value to get the selected data` _Reactive plots are just one way that marimo **makes your data tangible**._ #### Example[¶](#example_1 "Permanent link") `[](#__codelineno-7-1)import marimo as mo [](#__codelineno-7-2)import altair as alt [](#__codelineno-7-3)import vega_datasets [](#__codelineno-7-4)[](#__codelineno-7-5)# Load some data [](#__codelineno-7-6)cars = vega_datasets.data.cars() [](#__codelineno-7-7)[](#__codelineno-7-8)# Create an Altair chart [](#__codelineno-7-9)chart = alt.Chart(cars).mark_point().encode( [](#__codelineno-7-10) x='Horsepower', # Encoding along the x-axis [](#__codelineno-7-11) y='Miles_per_Gallon', # Encoding along the y-axis [](#__codelineno-7-12) color='Origin', # Category encoding by color [](#__codelineno-7-13)) [](#__codelineno-7-14)[](#__codelineno-7-15)# Make it reactive ⚡ [](#__codelineno-7-16)chart = mo.ui.altair_chart(chart)` `[](#__codelineno-8-1)# In a new cell, display the chart and its data filtered by the selection [](#__codelineno-8-2)mo.vstack([chart, chart.value.head()])` #### Learning Altair[¶](#learning-altair "Permanent link") If you're new to **Altair**, we highly recommend exploring the [Altair documentation](https://altair-viz.github.io/). Altair provides a declarative, concise, and simple way to create highly interactive and sophisticated plots. Altair is based on [Vega-Lite](https://vega.github.io/vega-lite/), an exceptional tool for creating interactive charts that serves as the backbone for marimo's reactive charting capabilities. ##### Concepts[¶](#concepts "Permanent link") Learn by doing? Skip this section! This section summarizes the main concepts used by Altair (and Vega-Lite). Feel free to skip this section and return later. Our choice to use the Vega-Lite specification was driven by its robust data model, which is well-suited for data analysis. Some key concepts are summarized below. (For a more detailed explanation, with examples, we recommend the [Basic Statistical Visualization](https://altair-viz.github.io/getting_started/starting.html) tutorial from Altair.) * **Data Source**: This is the information that will be visualized in the chart. It can be provided in various formats such as a dataframe, a list of dictionaries, or a URL pointing to the data source. * **Mark Type**: This refers to the visual representation used for each data point on the chart. The options include 'bar', 'dot', 'circle', 'area', and 'line'. Each mark type offers a different way to visualize and interpret the data. * **Encoding**: This is the process of mapping various aspects or dimensions of the data to visual characteristics of the marks. Encodings can be of different types: * **Positional Encodings**: These are encodings like 'x' and 'y' that determine the position of the marks in the chart. * **Categorical Encodings**: These are encodings like 'color' and 'shape' that categorize data points. They are typically represented in a legend for easy reference. * **Transformations**: These are operations that can be applied to the data before it is visualized, for example, filtering and aggregation. These transformations allow for more complex and nuanced visualizations. **Automatically interactive.** marimo adds interactivity automatically, based on the mark used and the encodings. For example, if you use a `mark_point` and an `x` encoding, marimo will automatically add a brush selection to the chart. If you add a `color` encoding, marimo will add a legend and a click selection. #### Automatic Selections[¶](#automatic-selections "Permanent link") By default [`mo.ui.altair_chart`](https://docs.marimo.io/api/plotting/#marimo.ui.altair_chart " marimo.ui.altair_chart") will make the chart and legend selectable. Depending on the mark type, the chart will either have a `point` or `interval` ("brush") selection. When using non-positional encodings (color, size, etc), [`mo.ui.altair_chart`](https://docs.marimo.io/api/plotting/#marimo.ui.altair_chart " marimo.ui.altair_chart") will also make the legend selectable. Selection configurable through `*_selection` params in [`mo.ui.altair_chart`](https://docs.marimo.io/api/plotting/#marimo.ui.altair_chart " marimo.ui.altair_chart"). See the [API docs](https://docs.marimo.io/api/plotting/#marimo.ui.altair_chart " marimo.ui.altair_chart") for details. Note You may still add your own selection parameters via Altair or Vega-Lite. marimo will not override your selections. #### Altair transformations[¶](#altair-transformations "Permanent link") Altair supports a variety of transformations, such as filtering, aggregation, and sorting. These transformations can be used to create more complex and nuanced visualizations. For example, you can use a filter to show only the points that meet a certain condition, or use an aggregation to show the average value of a variable. In order for marimo's reactive plots to work with transformations, you must install `vegafusion`, as this feature uses `chart.transformed_data` (which requires version 1.4.0 or greater of the `vegafusion` packages). `[](#__codelineno-9-1)# These can be installed with pip using: [](#__codelineno-9-2)pip install "vegafusion[embed]>=1.4.0" [](#__codelineno-9-3)# Or with conda using: [](#__codelineno-9-4)conda install -c conda-forge "vegafusion-python-embed>=1.4.0" "vegafusion>=1.4.0"` ### Plotly[¶](#plotly "Permanent link") Supported charts marimo can render any Plotly plot, but [`mo.ui.plotly`](https://docs.marimo.io/api/plotting/#marimo.ui.plotly " marimo.ui.plotly") only supports reactive selections for scatter/scattergl plots, bar charts, histograms, heatmaps, treemaps, and sunburst charts. If you require other kinds of selection, please [file an issue](https://github.com/marimo-team/marimo/issues). Use [`mo.ui.plotly`](https://docs.marimo.io/api/plotting/#marimo.ui.plotly " marimo.ui.plotly") to create selectable Plotly plots whose values are sent back to Python on selection. matplotlib[¶](#matplotlib_1 "Permanent link") --------------------------------------------- To output a matplotlib plot in a cell's output area, include its `Axes` or `Figure` object as the last expression in your notebook. For example: ``[](#__codelineno-11-1)plt.plot([1, 2]) [](#__codelineno-11-2)# plt.gca() gets the current `Axes` [](#__codelineno-11-3)plt.gca()`` or `[](#__codelineno-12-1)fig, ax = plt.subplots() [](#__codelineno-12-2)[](#__codelineno-12-3)ax.plot([1, 2]) [](#__codelineno-12-4)ax` If you want to output the plot in the console area, use `plt.show()` or `fig.show()`. ### Interactive plots with pan and zoom[¶](#interactive-plots-with-pan-and-zoom "Permanent link") To make matplotlib plots interactive with pan and zoom, use [mo.mpl.interactive](https://docs.marimo.io/api/plotting/#marimo.mpl.interactive " marimo.mpl.interactive"). This does not support reactive selection. Chart builder[¶](#chart-builder "Permanent link") ------------------------------------------------- marimo comes with a built-in chart builder that makes it easy to create plots specialized to your dataframes with just a few clicks. As you make your charts, marimo generates Python code that you can add to your notebook to save them. You can toggle the chart builder with a button at the bottom-left of a dataframe output. This provides a GUI interface to create many kinds of plots, while also generating Python code. Charts are powered by [Vega-Lite](https://vega.github.io/vega-lite/). To save a chart, click the `+` button in the `Python code` tab to add the code to a new cell. Note This feature is in active development. Please report any issues or feedback [here](https://github.com/marimo-team/marimo/issues). Basic execution - marimo https://docs.marimo.io/examples/running_cells/basics/ Tip: paste this code into an empty cell, and the marimo editor will create cells for you `import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo return (mo,) @app.cell(hide_code=True) def _(mo): mo.md(""" marimo knows how your cells are related, and can automatically update outputs like a spreadsheet. This eliminates hidden state and hidden bugs, accelerates data exploration, and makes it possible for marimo to run your notebooks as scripts and web apps. For expensive notebooks, you can [turn this behavior off](https://docs.marimo.io/guides/expensive_notebooks/) via the notebook footer. Try updating the values of variables below and see what happens! You can also try deleting a cell. """) return @app.cell def _(): x = 0 return (x,) @app.cell def _(): y = 1 return @app.cell def _(x): x return if __name__ == "__main__": app.run()` SQL - marimo https://docs.marimo.io/guides/working_with_data/sql.html Using SQL[¶](#using-sql "Permanent link") ----------------------------------------- marimo lets you mix and match **Python and SQL**: Use SQL to query Python dataframes (or databases like SQLite and Postgres), and get the query result back as a Python dataframe. > For a video overview on how to use SQL in marimo, watch our [YouTube tutorial](https://youtu.be/IHEf5HwU7R0). To create a SQL cell, you first need to install additional dependencies, including [duckdb](https://duckdb.org/): install with pipinstall with uvinstall with conda `[](#__codelineno-0-1)pip install "marimo[sql]"` `[](#__codelineno-2-1)conda install -c conda-forge marimo duckdb polars` Example[¶](#example "Permanent link") ------------------------------------- In this example notebook, we have a Pandas dataframe and a SQL cell that queries it. Notice that the query result is returned as a Python dataframe and usable in subsequent cells. Creating SQL cells[¶](#creating-sql-cells "Permanent link") ----------------------------------------------------------- You can create SQL cells in one of three ways: 1. **Right-click** an "add cell" button ("+" icon) next to a cell and choose "SQL cell" 2. Convert a empty cell to SQL via the cell context menu 3. Click the SQL button that appears at the bottom of the notebook Add SQL Cell This creates a "**SQL**" cell for you, which is syntactic sugar for Python code. The underlying code looks like: `[](#__codelineno-3-1)output_df = mo.sql(f"SELECT * FROM my_table LIMIT {max_rows.value}")` Notice that we have an **`output_df`** variable in the cell. This contains the query result, and is a Polars DataFrame (if you have `polars` installed) or a Pandas DataFrame (if you don't). One of them must be installed in order to interact with the query result. The SQL statement itself is an f-string, letting you interpolate Python values into the query with `{}`. In particular, this means your SQL queries can depend on the values of UI elements or other Python values, and they are fit into marimo's reactive dataflow graph. SQL Output Types[¶](#sql-output-types "Permanent link") ------------------------------------------------------- marimo supports different output types for SQL queries, which is particularly useful when working with large datasets. You can configure this in your application configuration in the top right of the marimo editor. The available options are: * `native`: Uses DuckDB's native lazy relation (recommended for best performance) * `lazy-polars`: Returns a lazy Polars DataFrame * `pandas`: Returns a Pandas DataFrame * `polars`: Returns an eager Polars DataFrame * `auto`: Automatically chooses based on installed packages (first tries `polars` then `pandas`) For best performance with large datasets, we recommend using `native` to avoid loading the entire result set into memory and to more easily chain SQL cells together. By default, only the first 10 rows are displayed in the UI to prevent memory issues. Set a default The default output type is currently `auto`, but we recommend explicitly setting the output type to `native` for best performance with large datasets or `polars` if you need to work with the results in Python code. You can configure this in your application settings. Reference a local dataframe[¶](#reference-a-local-dataframe "Permanent link") ----------------------------------------------------------------------------- You can reference a local dataframe in your SQL cell by using the name of the Python variable that holds the dataframe. If you have a database connection with a table of the same name, the database table will be used instead. Reference a dataframe Since the output dataframe variable (`_df`) has an underscore, making it private, it is not referenceable from other cells. Reference the output of a SQL cell[¶](#reference-the-output-of-a-sql-cell "Permanent link") ------------------------------------------------------------------------------------------- Defining a non-private (non-underscored) output variable in the SQL cell allows you to reference the resulting dataframe in other Python and SQL cells. Reference the SQL result Querying files, databases, and APIs[¶](#querying-files-databases-and-apis "Permanent link") ------------------------------------------------------------------------------------------- In the above example, you may have noticed we queried an HTTP endpoint instead of a local dataframe. We are not only limited to querying local dataframes; we can also query files, databases such as Postgres and SQLite, and APIs: `[](#__codelineno-4-1)-- or [](#__codelineno-4-2)SELECT * FROM 's3://my-bucket/file.parquet'; [](#__codelineno-4-3)-- or [](#__codelineno-4-4)SELECT * FROM read_csv('path/to/example.csv'); [](#__codelineno-4-5)-- or [](#__codelineno-4-6)SELECT * FROM read_parquet('path/to/example.parquet');` For a full list you can check out the [duckdb extensions](https://duckdb.org/docs/extensions/overview). You can also check out our [examples on GitHub](https://github.com/marimo-team/marimo/tree/main/examples/sql). Escaping SQL brackets[¶](#escaping-sql-brackets "Permanent link") ----------------------------------------------------------------- Our "SQL" cells are really just Python under the hood to keep notebooks as pure Python scripts. By default, we use `f-strings` for SQL strings, which allows for parameterized SQL like `SELECT * from table where value < {min}`. To escape real `{`/`}` that you don't want parameterized, use double `{{...}}`: `[](#__codelineno-5-1)SELECT unnest([{{'a': 42, 'b': 84}}, {{'a': 100, 'b': NULL}}]);` Connecting to a custom database[¶](#connecting-to-a-custom-database "Permanent link") ------------------------------------------------------------------------------------- There are two ways to connect to a database in marimo: ### 1\. Using the UI[¶](#1-using-the-ui "Permanent link") Click the "Add Database Connection" button in your notebook to connect to PostgreSQL, MySQL, SQLite, DuckDB, Snowflake, or BigQuery databases. The UI will guide you through entering your connection details securely. Environment variables picked up from your [`dotenv`](https://docs.marimo.io/configuration/runtime_configuration/#environment-variables) can be used to fill out the database configuration fields. Add a database connection through the UI If you'd like to connect to a database that isn't supported by the UI, you can use the code method below, or submit a [feature request](https://github.com/marimo-team/marimo/issues/new?title=New%20database%20connection:&labels=enhancement&template=feature_request.yaml). ### 2\. Using Code[¶](#2-using-code "Permanent link") You can bring your own database via a **connection engine** with one of the following libraries * [SQLAlchemy](https://docs.sqlalchemy.org/en/20/core/connections.html#basic-usage) * [SQLModel](https://sqlmodel.tiangolo.com/tutorial/create-db-and-table/?h=create+engine#create-the-engine) * [Ibis](https://ibis-project.org/backends/athena) * [Custom DuckDB connection](https://duckdb.org/docs/api/python/overview.html#connection-options) * [ClickHouse Connect](https://clickhouse.com/docs/integrations/python#introduction) * [chDB](https://clickhouse.com/docs/chdb) By default, marimo uses the [in-memory duckdb connection](https://duckdb.org/docs/connect/overview.html#in-memory-database). List of supported databases Updated: 2025-04-30. This list is not exhaustive. | Database | Library | | --- | --- | | Amazon Athena | `sqlalchemy`, `sqlmodel`, `ibis` | | Amazon Redshift | `sqlalchemy`, `sqlmodel` | | Apache Drill | `sqlalchemy`, `sqlmodel` | | Apache Druid | `sqlalchemy`, `sqlmodel`, `ibis` | | Apache Hive and Presto | `sqlalchemy`, `sqlmodel` | | Apache Solr | `sqlalchemy`, `sqlmodel` | | BigQuery | `sqlalchemy`, `sqlmodel`, `ibis` | | ClickHouse | `clickhouse_connect`, `chdb` | | CockroachDB | `sqlalchemy`, `sqlmodel` | | Databricks | `sqlalchemy`, `sqlmodel`, `ibis` | | dlt | `ibis` | | Datafusion | `ibis` | | DuckDB | `duckdb` | | EXASolution | `sqlalchemy`, `sqlmodel`, `ibis` | | Elasticsearch (readonly) | `sqlalchemy`, `sqlmodel` | | Firebolt | `sqlalchemy`, `sqlmodel` | | Flink | `ibis` | | Google Sheets | `sqlalchemy`, `sqlmodel` | | Impala | `sqlalchemy`, `sqlmodel`, `ibis` | | Microsoft Access | `sqlalchemy`, `sqlmodel` | | Microsoft SQL Server | `sqlalchemy`, `sqlmodel`, `ibis` | | MonetDB | `sqlalchemy`, `sqlmodel` | | MySQL | `sqlalchemy`, `sqlmodel`, `ibis` | | OpenGauss | `sqlalchemy`, `sqlmodel` | | Oracle | `sqlalchemy`, `sqlmodel`, `ibis` | | PostgreSQL | `sqlalchemy`, `sqlmodel`, `ibis` | | PySpark | `ibis` | | RisingWave | `ibis` | | SAP HANA | `sqlalchemy`, `sqlmodel` | | Snowflake | `sqlalchemy`, `sqlmodel`, `ibis` | | SQLite | `sqlalchemy`, `sqlmodel`, `ibis` | | Teradata Vantage | `sqlalchemy`, `sqlmodel` | | TimePlus | `sqlalchemy`, `sqlmodel` | | Trino | `sqlalchemy`, `sqlmodel`, `ibis` | Define the engine as a Python variable in a cell: SQLAlchemySQLModelIbisDuckDBClickHouse ConnectchDB `[](#__codelineno-6-1)import sqlalchemy [](#__codelineno-6-2)[](#__codelineno-6-3)# Create an in-memory SQLite database with SQLAlchemy [](#__codelineno-6-4)sqlite_engine = sqlalchemy.create_engine("sqlite:///:memory:")` `[](#__codelineno-7-1)import sqlmodel [](#__codelineno-7-2)[](#__codelineno-7-3)# Create an in-memory SQLite database with SQLModel [](#__codelineno-7-4)sqlite_engine = sqlmodel.create_engine("sqlite:///:memory:")` `[](#__codelineno-8-1)import ibis [](#__codelineno-8-2)[](#__codelineno-8-3)# Create an in-memory SQLite database with Ibis [](#__codelineno-8-4)sqlite_engine = ibis.connect("sqlite:///:memory:")` `[](#__codelineno-9-1)import duckdb [](#__codelineno-9-2)[](#__codelineno-9-3)# Create a DuckDB connection [](#__codelineno-9-4)duckdb_conn = duckdb.connect("file.db")` ClickHouse Connect enables remote connections to ClickHouse databases. Refer to [the official docs](https://clickhouse.com/docs/integrations/python#gather-your-connection-details) for more configuration options. `[](#__codelineno-10-1)import clickhouse_connect [](#__codelineno-10-2)[](#__codelineno-10-3)engine = clickhouse_connect.get_client(host="localhost", port=8123, username="default", password="password")` Warning chDB is still new. You may experience issues with your queries. We recommend only using one connection at a time. Refer to [chDB docs](https://github.com/orgs/chdb-io/discussions/295) for more information. `[](#__codelineno-11-1)import chdb [](#__codelineno-11-2)[](#__codelineno-11-3)connection = chdb.connect(":memory:") [](#__codelineno-11-4)[](#__codelineno-11-5)# Supported formats with examples: [](#__codelineno-11-6)":memory:" # In-memory database [](#__codelineno-11-7)"test.db" # Relative path [](#__codelineno-11-8)"file:test.db" # Explicit file protocol [](#__codelineno-11-9)"/path/to/test.db" # Absolute path [](#__codelineno-11-10)"file:/path/to/test.db" # Absolute path with protocol [](#__codelineno-11-11)"file:test.db?param1=value1¶m2=value2" # With query parameters [](#__codelineno-11-12)"file::memory:?verbose&log-level=test" # In-memory with parameters [](#__codelineno-11-13)"///path/to/test.db?param1=value1" # Triple slash absolute path` marimo will auto-discover the engine and let you select it in the SQL cell's connection dropdown. Choose a custom database connection Database, schema, and table auto-discovery[¶](#database-schema-and-table-auto-discovery "Permanent link") --------------------------------------------------------------------------------------------------------- marimo will automatically discover the database connection and display the database, schemas, tables, and columns in the Data Sources panel. This panels lets you quickly navigate your database schema and reference tables and columns to pull in your SQL queries. Data Sources panel Note By default, marimo auto-discovers databases and schemas, but not tables and columns (to avoid performance issues with large databases). You can configure this behavior in your `pyproject.toml` file. Options are `true`, `false`, or `"auto"`. `"auto"` will determine whether to auto-discover based on the type of database (e.g. when the value is `"auto"`, Snowflake and BigQuery will not auto-discover tables and columns while SQLite, Postgres, and MySQL will): pyproject.toml `[](#__codelineno-12-1)[tool.marimo.datasources] [](#__codelineno-12-2)auto_discover_schemas = true # Default: true [](#__codelineno-12-3)auto_discover_tables = "auto" # Default: "auto" [](#__codelineno-12-4)auto_discover_columns = "auto" # Default: false` Catalogs[¶](#catalogs "Permanent link") --------------------------------------- marimo supports connecting to Iceberg catalogs. You can click the "+" button in the Datasources panel or manually create a [PyIceberg](https://py.iceberg.apache.org/) `Catalog` connection. PyIceberg supports a variety of catalog implementations including REST, SQL, Glue, DynamoDB, and more. `[](#__codelineno-13-1)from pyiceberg.catalog.rest import RestCatalog [](#__codelineno-13-2)[](#__codelineno-13-3)catalog = RestCatalog( [](#__codelineno-13-4) name="catalog", [](#__codelineno-13-5) warehouse="1234567890", [](#__codelineno-13-6) uri="https://my-catalog.com", [](#__codelineno-13-7) token="my-token", [](#__codelineno-13-8))` Catalogs will appear in the Datasources panel, but they cannot be used as an engine in SQL cells. However, you can still load the table and use it in subsequent Python or SQL cells. `[](#__codelineno-14-1)df = catalog.load_table(("my-namespace", "my-table")).to_polars()` Utilities[¶](#utilities "Permanent link") ----------------------------------------- marimo provides a few utilities when working with SQL **SQL Linter** Lint your SQL code and provide better autocompletions and error highlighting. To disable the linter, you can set the `sql_linter` configuration to `false` in your `pyproject.toml` file or disable it in the marimo editor's settings menu. **SQL Formatting** Click on the paint roller icon at the bottom right of the SQL cell to format your SQL code. **SQL Mode** For In-Memory DuckDB, marimo offers a Validate mode that will validate your SQL as you write it. Under the hood, this runs a debounced query in EXPLAIN mode and returns the parsed errors. Interactive tutorial[¶](#interactive-tutorial "Permanent link") --------------------------------------------------------------- For an interactive tutorial, run at your command-line. Examples[¶](#examples "Permanent link") --------------------------------------- Check out our [examples on GitHub](https://github.com/marimo-team/marimo/tree/main/examples/sql). Getting around multiple definition errors - marimo https://docs.marimo.io/examples/running_cells/multiple_definitions/ Tip: paste this code into an empty cell, and the marimo editor will create cells for you `# /// script # requires-python = ">=3.12" # dependencies = [ # "marimo", # "matplotlib==3.10.1", # ] # /// import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo return (mo,) @app.cell(hide_code=True) def _(mo): mo.md(r""" ## Use local variables Variables prefixed with an underscore are local to a cell, and can be redefined. """) return @app.cell def _(): for _i in range(3): print(_i) return @app.cell def _(): for _i in range(4, 6): print(_i) return @app.cell def _(): # _i is not defined in this cell _i return @app.cell(hide_code=True) def _(mo): mo.md(r""" ## Wrap code in functions Wrap cells in functions to minimize the number of temporary globals you introduce. """) return @app.cell def _(): import matplotlib.pyplot as plt return (plt,) @app.cell def _(plt): def _(): fig, ax = plt.subplots() plt.plot([1, 2]) return ax _() return if __name__ == "__main__": app.run()` Stopping execution - marimo https://docs.marimo.io/examples/running_cells/stop/ Source code for `examples/control_flow/stop_execution.py` Tip: paste this code into an empty cell, and the marimo editor will create cells for you `import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(mo): button = mo.ui.run_button() button return (button,) @app.cell def _(button, mo): mo.stop(not button.value, "Click the button to continue") mo.md("# :tada:") return if __name__ == "__main__": app.run()` Run on button click - marimo https://docs.marimo.io/examples/running_cells/run_button/ Tip: paste this code into an empty cell, and the marimo editor will create cells for you `import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(mo): first_button = mo.ui.run_button(label="Option 1") second_button = mo.ui.run_button(label="Option 2") first_button, second_button return first_button, second_button @app.cell def _(first_button, second_button): if first_button.value: print("You chose option 1!") elif second_button.value: print("You chose option 2!") else: print("Click a button!") return if __name__ == "__main__": app.run()` Run on button click - marimo https://docs.marimo.io/examples/running_cells/async_await/ marimo lets you use `await` to execute `async` functions. Source code for `examples/running_cells/async_await.py` Tip: paste this code into an empty cell, and the marimo editor will create cells for you `import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo return @app.function async def wait_for(seconds): import asyncio print(f"Waiting for {seconds} seconds ...") await asyncio.sleep(seconds) print("Done!") @app.cell async def _(): await wait_for(1) return if __name__ == "__main__": app.run()` Refresh cells on a timer - marimo https://docs.marimo.io/examples/running_cells/refresh/ Use [`mo.ui.refresh`](https://docs.marimo.io/api/inputs/refresh/#marimo.ui.refresh " marimo.ui.refresh") to run a cell on a timer Source code for `examples/ui/refresh.py` Tip: paste this code into an empty cell, and the marimo editor will create cells for you `import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(mo): refresh = mo.ui.refresh(default_interval=1) refresh return (refresh,) @app.cell def _(refresh): print(refresh.value) return if __name__ == "__main__": app.run()` In-memory caching - marimo https://docs.marimo.io/examples/running_cells/memory_cache/ Tip: paste this code into an empty cell, and the marimo editor will create cells for you ``import marimo __generated_with = "0.19.7" app = marimo.App(app_title="In Memory Cache") @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(mo): @mo.cache def sleep_for(t: int): import time print("Sleeping") time.sleep(t) return t return (sleep_for,) @app.cell(hide_code=True) def _(mo): mo.md(""" Use `mo.cache` to cache the outputs of expensive functions. The first time the function is called with unseen arguments, it will execute and return the computed value. Subsequent calls with the same arguments will return cached results. Experiment with the invocation below to get a feel for how this works. """) return @app.cell def _(sleep_for): sleep_for(1) return if __name__ == "__main__": app.run()`` Debugging - marimo https://docs.marimo.io/examples/running_cells/debugging/ marimo lets you use PDB to debug cells. Insert a breakpoint by typing `breakpoint()`: `[](#__codelineno-0-1)x = 0 [](#__codelineno-0-2)breakpoint() [](#__codelineno-0-3)1 / x` Persistent caching - marimo https://docs.marimo.io/examples/running_cells/persistent_cache/ Use [`mo.persistent_cache`](https://docs.marimo.io/api/caching/#marimo.persistent_cache " marimo.persistent_cache") to cache the output of expensive computations to persistent storage (like disk). Source code for `examples/running_cells/persistent_cache.py` Tip: paste this code into an empty cell, and the marimo editor will create cells for you ``import marimo __generated_with = "0.19.7" app = marimo.App(app_title="In Memory Cache") @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(mo): @mo.persistent_cache def sleep_for(t: int): import time print("Sleeping") time.sleep(t) return t return (sleep_for,) @app.cell(hide_code=True) def _(mo): mo.md(""" Use `mo.persistent_cache` to cache the outputs of expensive computations to persistent storage. The first time the function is called with unseen arguments, it will execute and return the computed value. Subsequent calls with the same arguments will return cached results. Experiment with the invocation below to get a feel for how this works. """) return @app.cell def _(sleep_for): sleep_for(1) return if __name__ == "__main__": app.run()`` Cell output - marimo https://docs.marimo.io/examples/outputs/basic_output/ Tip: paste this code into an empty cell, and the marimo editor will create cells for you `import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(mo): mo.md(""" The last expression of a cell is its visual output. This output appears above the cell when editing a notebook, with notebook code serving as a "caption" for the output. Outputs can be configured to appear below cells in the user settings. If running a notebook as an app, the output is the visual representation of the cell (code is hidden by default). """) return @app.cell def _(): "Hello, world!" return @app.cell def _(): import marimo as mo return (mo,) if __name__ == "__main__": app.run()` Basic markdown - marimo https://docs.marimo.io/examples/outputs/basic_markdown/ Tip: paste this code into an empty cell, and the marimo editor will create cells for you ``import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo return (mo,) @app.cell(hide_code=True) def _(mo): mo.md(""" Create a "Markdown" cell by clicking the `Markdown` button below, or through the cell action menu. Markdown is represented as Python under-the-hood, using the `mo.md()` function — so you'll need to import marimo as mo into your notebook first! """) return if __name__ == "__main__": app.run()`` Console outputs - marimo https://docs.marimo.io/examples/outputs/console_outputs/ Tip: paste this code into an empty cell, and the marimo editor will create cells for you `import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(mo): print("This is a console output") print("Notice that it's below the cell.") print("You can configure where outputs show up in your user configuration.") mo.md( "This is a cell output. Console outputs show up below a cell; cell outputs show up above." ) return if __name__ == "__main__": app.run()` Capture console outputs - marimo https://docs.marimo.io/examples/outputs/capture_console_outputs/ You can capture console outputs with marimo utility functions. Learn more in the [API reference](https://docs.marimo.io/api/outputs/#console-outputs). Source code for `examples/outputs/capture_console_outputs.py` Tip: paste this code into an empty cell, and the marimo editor will create cells for you `import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(mo): with mo.capture_stdout() as output: print("Hello, world") mo.md(output.getvalue()) return if __name__ == "__main__": app.run()` Showing plots - marimo https://docs.marimo.io/examples/outputs/plots/ Tip: paste this code into an empty cell, and the marimo editor will create cells for you ``# /// script # requires-python = ">=3.12" # dependencies = [ # "marimo", # "matplotlib==3.10.1", # "numpy==2.2.4", # ] # /// import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(): import matplotlib.pyplot as plt return (plt,) @app.cell(hide_code=True) def _(mo): mo.md(""" Output a plot object, such as an axis or figure, to see the plot. """) return @app.cell def _(plt): import numpy as np x = np.linspace(0, 10) plt.plot(x, x**2) plt.gca() return (x,) @app.cell(hide_code=True) def _(mo): mo.md(""" Calling `show()` methods displays the plot in the console area, which can be helpful for debugging because console outputs do not show up in the "app" preview. """) return @app.cell def _(plt, x): plt.plot(x, x**3) plt.show() return @app.cell(hide_code=True) def _(mo): mo.md(""" Wrap an `Axes` in `mo.ui.matplotlib` to enable reactive selections. Click-drag for box selection, shift-drag for lasso selection. """) return @app.cell def _(mo, np, plt): _x = np.random.randn(200) _y = np.random.randn(200) plt.scatter(_x, _y) scatter_fig = mo.ui.matplotlib(plt.gca()) scatter_fig return (scatter_fig,) @app.cell def _(scatter_fig): scatter_fig.value return if __name__ == "__main__": app.run()`` Showing multiple outputs - marimo https://docs.marimo.io/examples/outputs/multiple_outputs/ See the [API reference on outputs](https://docs.marimo.io/api/outputs/) for more info. Source code for `examples/outputs/showing_multiple_outputs.py` Tip: paste this code into an empty cell, and the marimo editor will create cells for you `import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(mo): for i in range(3): mo.output.append(mo.md(f"$i = {i}$")) mo.output.append(mo.md("Completed iteration.")) return if __name__ == "__main__": app.run()` Conditionally showing outputs - marimo https://docs.marimo.io/examples/outputs/conditional_output/ Tip: paste this code into an empty cell, and the marimo editor will create cells for you ``import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(mo): checkbox = mo.ui.checkbox() checkbox return (checkbox,) @app.cell(hide_code=True) def _(mo): mo.md(""" Use inline if expressions to conditionally show a value """) return @app.cell def _(checkbox): "Checkbox is checked" if checkbox.value else "Checkbox is not checked" return @app.cell(hide_code=True) def _(mo): mo.md(""" The following cell would **not** show anything, since an if statement does not have a value: ```python # Intentionally demonstrates that if statements don't display expressions # Using _ to suppress the lint warning while keeping the example if checkbox.value: mo.md("Checkbox is checked") else: mo.md("Checkbox is not checked") ``` """) return @app.cell(hide_code=True) def _(mo): mo.md(""" A value of `None` produces the empty output: """) return @app.cell def _(checkbox): checkbox return @app.cell def _(checkbox, mo): _output = None if checkbox.value: _output = mo.md("Checkbox is checked.") _output return if __name__ == "__main__": app.run()`` Dynamic markdown - marimo https://docs.marimo.io/examples/markdown/dynamic_markdown/ Tip: paste this code into an empty cell, and the marimo editor will create cells for you ``import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell(hide_code=True) def _(mo): mo.md(r""" Use `mo.md` with an `f-string` to create markdown that depends on the value of Python objects. """) return @app.cell def _(): name = "Alice" return (name,) @app.cell def _(mo, name): mo.md( f""" Hello, {name}! """ ) return @app.cell(hide_code=True) def _(mo): mo.md(r""" Embed marimo UI elements in markdown directly: """) return @app.cell def _(mo): text_input = mo.ui.text(placeholder="My name is ...", debounce=False) return (text_input,) @app.cell def _(mo, text_input): mo.md( f""" What's your name? {text_input} Hello, {text_input.value}! """ ) return @app.cell(hide_code=True) def _(mo): mo.md(r""" Wrap plots and data structures in `mo.as_html()` to hook into marimo's rich media viewer: """) return @app.cell def _(mo): mo.md( f""" Here's a list of numbers: {mo.as_html([1, 2, 3])} """ ) return @app.cell def _(): import marimo as mo return (mo,) if __name__ == "__main__": app.run()`` Dynamic markdown - marimo https://docs.marimo.io/examples/markdown/dynamic_markdown Tip: paste this code into an empty cell, and the marimo editor will create cells for you ``import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell(hide_code=True) def _(mo): mo.md(r""" Use `mo.md` with an `f-string` to create markdown that depends on the value of Python objects. """) return @app.cell def _(): name = "Alice" return (name,) @app.cell def _(mo, name): mo.md( f""" Hello, {name}! """ ) return @app.cell(hide_code=True) def _(mo): mo.md(r""" Embed marimo UI elements in markdown directly: """) return @app.cell def _(mo): text_input = mo.ui.text(placeholder="My name is ...", debounce=False) return (text_input,) @app.cell def _(mo, text_input): mo.md( f""" What's your name? {text_input} Hello, {text_input.value}! """ ) return @app.cell(hide_code=True) def _(mo): mo.md(r""" Wrap plots and data structures in `mo.as_html()` to hook into marimo's rich media viewer: """) return @app.cell def _(mo): mo.md( f""" Here's a list of numbers: {mo.as_html([1, 2, 3])} """ ) return @app.cell def _(): import marimo as mo return (mo,) if __name__ == "__main__": app.run()`` Mermaid - marimo https://docs.marimo.io/examples/markdown/mermaid/ Tip: paste this code into an empty cell, and the marimo editor will create cells for you ``# /// script # requires-python = ">=3.11" # dependencies = [ # "marimo", # ] # /// import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(mo): mo.mermaid( """ graph TD A[Enter Chart Definition] --> B(Preview) B --> C{decide} C --> D[Keep] C --> E[Edit Definition] E --> B D --> F[Save Image and Code] F --> B """ ).center() return @app.cell def _(mo): graph = mo.ui.code_editor( value="""sequenceDiagram Alice->>John: Hello John, how are you? John-->>Alice: Great! Alice-)John: See you later!""", language="md", label="Mermaid editor", ) graph return (graph,) @app.cell def _(graph, mo): mo.mermaid(graph.value).text return @app.cell def _(graph, mo): mo.md(f""" You can render mermaid directly inside `mo.md`. Using `mo.mermaid()` {mo.mermaid(graph.value).text} """) return if __name__ == "__main__": app.run()`` Mermaid - marimo https://docs.marimo.io/examples/markdown/mermaid Tip: paste this code into an empty cell, and the marimo editor will create cells for you ``# /// script # requires-python = ">=3.11" # dependencies = [ # "marimo", # ] # /// import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(mo): mo.mermaid( """ graph TD A[Enter Chart Definition] --> B(Preview) B --> C{decide} C --> D[Keep] C --> E[Edit Definition] E --> B D --> F[Save Image and Code] F --> B """ ).center() return @app.cell def _(mo): graph = mo.ui.code_editor( value="""sequenceDiagram Alice->>John: Hello John, how are you? John-->>Alice: Great! Alice-)John: See you later!""", language="md", label="Mermaid editor", ) graph return (graph,) @app.cell def _(graph, mo): mo.mermaid(graph.value).text return @app.cell def _(graph, mo): mo.md(f""" You can render mermaid directly inside `mo.md`. Using `mo.mermaid()` {mo.mermaid(graph.value).text} """) return if __name__ == "__main__": app.run()`` Admonitions - marimo https://docs.marimo.io/examples/markdown/admonitions marimo supports admonition blocks using the [PyMdown Extensions Blocks](https://facelessuser.github.io/pymdown-extensions/extensions/blocks/) syntax. See the [Admonition plugin docs](https://facelessuser.github.io/pymdown-extensions/extensions/blocks/plugins/admonition/) for the full format and options. Source code for `examples/markdown/admonitions.py` Tip: paste this code into an empty cell, and the marimo editor will create cells for you `import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell(hide_code=True) def _(mo): mo.md(r""" Use **admonitions** in markdown to bring attention to text. Here are some examples. """) return @app.cell def _(mo): mo.md(""" /// admonition | Heads up. Here's some information. /// """) return @app.cell def _(mo): mo.md(""" /// attention | Attention! This is important. /// """) return @app.cell def _(): import marimo as mo return (mo,) if __name__ == "__main__": app.run()` Admonitions - marimo https://docs.marimo.io/examples/markdown/admonitions/ marimo supports admonition blocks using the [PyMdown Extensions Blocks](https://facelessuser.github.io/pymdown-extensions/extensions/blocks/) syntax. See the [Admonition plugin docs](https://facelessuser.github.io/pymdown-extensions/extensions/blocks/plugins/admonition/) for the full format and options. Source code for `examples/markdown/admonitions.py` Tip: paste this code into an empty cell, and the marimo editor will create cells for you `import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell(hide_code=True) def _(mo): mo.md(r""" Use **admonitions** in markdown to bring attention to text. Here are some examples. """) return @app.cell def _(mo): mo.md(""" /// admonition | Heads up. Here's some information. /// """) return @app.cell def _(mo): mo.md(""" /// attention | Attention! This is important. /// """) return @app.cell def _(): import marimo as mo return (mo,) if __name__ == "__main__": app.run()` Details - marimo https://docs.marimo.io/examples/markdown/details/ Tip: paste this code into an empty cell, and the marimo editor will create cells for you ``import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell(hide_code=True) def _(mo): mo.md(r""" Create expandable markdown blocks with `details`: """) return @app.cell def _(mo): mo.md(""" /// details | Hello, details! Some additional content. /// """) return @app.cell(hide_code=True) def _(mo): mo.md(r""" Style details using the "type" argument: """) return @app.cell def _(mo): mo.md(""" /// details | Info details type: info Some additional content. /// """) return @app.cell def _(mo): mo.md(""" /// details | Warning details type: warn This highlights something to watch out for /// """) return @app.cell def _(mo): mo.md(""" /// details | Danger details type: danger This indicates a critical warning or dangerous situation /// """) return @app.cell def _(mo): mo.md(""" /// details | Success details type: success This indicates a successful outcome or positive note /// """) return @app.cell def _(): import marimo as mo return (mo,) if __name__ == "__main__": app.run()`` Details - marimo https://docs.marimo.io/examples/markdown/details Tip: paste this code into an empty cell, and the marimo editor will create cells for you ``import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell(hide_code=True) def _(mo): mo.md(r""" Create expandable markdown blocks with `details`: """) return @app.cell def _(mo): mo.md(""" /// details | Hello, details! Some additional content. /// """) return @app.cell(hide_code=True) def _(mo): mo.md(r""" Style details using the "type" argument: """) return @app.cell def _(mo): mo.md(""" /// details | Info details type: info Some additional content. /// """) return @app.cell def _(mo): mo.md(""" /// details | Warning details type: warn This highlights something to watch out for /// """) return @app.cell def _(mo): mo.md(""" /// details | Danger details type: danger This indicates a critical warning or dangerous situation /// """) return @app.cell def _(mo): mo.md(""" /// details | Success details type: success This indicates a successful outcome or positive note /// """) return @app.cell def _(): import marimo as mo return (mo,) if __name__ == "__main__": app.run()`` Dataframes - marimo https://docs.marimo.io/examples/outputs/dataframes/ Tip: paste this code into an empty cell, and the marimo editor will create cells for you `# /// script # requires-python = ">=3.12" # dependencies = [ # "marimo", # "vega-datasets==0.9.0", # ] # /// import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(): from vega_datasets import data return (data,) @app.cell def _(data): df = data.cars() return (df,) @app.cell(hide_code=True) def _(mo): mo.md(""" marimo has a rich dataframe viewer built-in: - built-in global search - per-column sorting and filtering - per-column histograms - download filtered views - paginate through the whole dataframe """) return @app.cell def _(df): df return if __name__ == "__main__": app.run()` Emoji - marimo https://docs.marimo.io/examples/markdown/emoji/ Source code for `examples/markdown/emoji.py` Tip: paste this code into an empty cell, and the marimo editor will create cells for you `import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell(hide_code=True) def _(mo): mo.md(r""" Use colon syntax as a shortcut for **emojis** in your markdown. """) return @app.cell def _(mo): mo.md(r""" :rocket: :smile: """) return @app.cell def _(): import marimo as mo return (mo,) if __name__ == "__main__": app.run()` Dataframes - marimo https://docs.marimo.io/examples/outputs/dataframes Tip: paste this code into an empty cell, and the marimo editor will create cells for you `# /// script # requires-python = ">=3.12" # dependencies = [ # "marimo", # "vega-datasets==0.9.0", # ] # /// import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(): from vega_datasets import data return (data,) @app.cell def _(data): df = data.cars() return (df,) @app.cell(hide_code=True) def _(mo): mo.md(""" marimo has a rich dataframe viewer built-in: - built-in global search - per-column sorting and filtering - per-column histograms - download filtered views - paginate through the whole dataframe """) return @app.cell def _(df): df return if __name__ == "__main__": app.run()` Table - marimo https://docs.marimo.io/api/inputs/table `[](#__codelineno-0-1)table( [](#__codelineno-0-2) data: ListOrTuple[ [](#__codelineno-0-3) str | int | float | bool | MIME | None [](#__codelineno-0-4) ] [](#__codelineno-0-5) | ListOrTuple[dict[str, JSONType]] [](#__codelineno-0-6) | dict[str, ListOrTuple[JSONType]] [](#__codelineno-0-7) | IntoDataFrame, [](#__codelineno-0-8) pagination: bool | None = None, [](#__codelineno-0-9) selection: Literal[ [](#__codelineno-0-10) "single", "multi", "single-cell", "multi-cell" [](#__codelineno-0-11) ] [](#__codelineno-0-12) | None = "multi", [](#__codelineno-0-13) initial_selection: list[int] [](#__codelineno-0-14) | list[tuple[str, str]] [](#__codelineno-0-15) | None = None, [](#__codelineno-0-16) page_size: int | None = None, [](#__codelineno-0-17) show_column_summaries: ShowColumnSummaries [](#__codelineno-0-18) | None = None, [](#__codelineno-0-19) show_data_types: bool = True, [](#__codelineno-0-20) format_mapping: dict[str, str | Callable[..., Any]] [](#__codelineno-0-21) | None = None, [](#__codelineno-0-22) freeze_columns_left: Sequence[str] | None = None, [](#__codelineno-0-23) freeze_columns_right: Sequence[str] | None = None, [](#__codelineno-0-24) text_justify_columns: dict[ [](#__codelineno-0-25) str, Literal["left", "center", "right"] [](#__codelineno-0-26) ] [](#__codelineno-0-27) | None = None, [](#__codelineno-0-28) wrapped_columns: list[str] | None = None, [](#__codelineno-0-29) header_tooltip: dict[str, str] | None = None, [](#__codelineno-0-30) show_download: bool = True, [](#__codelineno-0-31) max_columns: MaxColumnsType = MAX_COLUMNS_NOT_PROVIDED, [](#__codelineno-0-32) *, [](#__codelineno-0-33) label: str = "", [](#__codelineno-0-34) on_change: Callable[ [](#__codelineno-0-35) [ [](#__codelineno-0-36) Union[ [](#__codelineno-0-37) list[JSONType], [](#__codelineno-0-38) dict[str, ListOrTuple[JSONType]], [](#__codelineno-0-39) IntoDataFrame, [](#__codelineno-0-40) list[TableCell], [](#__codelineno-0-41) ] [](#__codelineno-0-42) ], [](#__codelineno-0-43) None, [](#__codelineno-0-44) ] [](#__codelineno-0-45) | None = None, [](#__codelineno-0-46) style_cell: Callable[[str, str, Any], dict[str, Any]] [](#__codelineno-0-47) | None = None, [](#__codelineno-0-48) hover_template: str [](#__codelineno-0-49) | Callable[[str, str, Any], str] [](#__codelineno-0-50) | None = None, [](#__codelineno-0-51) max_height: int | None = None, [](#__codelineno-0-52) _internal_column_charts_row_limit: int | None = None, [](#__codelineno-0-53) _internal_summary_row_limit: int | None = None, [](#__codelineno-0-54) _internal_total_rows: int [](#__codelineno-0-55) | Literal["too_many"] [](#__codelineno-0-56) | None = None, [](#__codelineno-0-57) _internal_lazy: bool = False, [](#__codelineno-0-58) _internal_preload: bool = False, [](#__codelineno-0-59))` Bases: `UIElement[list[str] | list[int] | list[dict[str, Any]], list[JSONType] | IntoDataFrame | list[TableCell]]` A table component with selectable rows. Get the selected rows with `table.value`. The table data can be supplied as: 1. a list of dicts, with one dict for each row, keyed by column names; 2. a list of values, representing a table with a single column; 3. a Pandas dataframe; or 4. a Polars dataframe; or 5. an Ibis dataframe; or 6. a PyArrow table. Examples: Create a table from a list of dicts, one for each row: `[](#__codelineno-0-1)table = mo.ui.table( [](#__codelineno-0-2) data=[ [](#__codelineno-0-3) {"first_name": "Michael", "last_name": "Scott"}, [](#__codelineno-0-4) {"first_name": "Dwight", "last_name": "Schrute"}, [](#__codelineno-0-5) ], [](#__codelineno-0-6) label="Users", [](#__codelineno-0-7))` Create a table from a single column of data: `[](#__codelineno-1-1)table = mo.ui.table( [](#__codelineno-1-2) data=[ [](#__codelineno-1-3) {"first_name": "Michael", "last_name": "Scott"}, [](#__codelineno-1-4) {"first_name": "Dwight", "last_name": "Schrute"}, [](#__codelineno-1-5) ], [](#__codelineno-1-6) label="Users", [](#__codelineno-1-7))` Create a table from a dataframe: `[](#__codelineno-2-1)# df is a Pandas or Polars dataframe [](#__codelineno-2-2)table = mo.ui.table( [](#__codelineno-2-3) data=df, [](#__codelineno-2-4) # use pagination when your table has many rows [](#__codelineno-2-5) pagination=True, [](#__codelineno-2-6) label="Dataframe", [](#__codelineno-2-7))` Create a table with format mapping: `[](#__codelineno-3-1)# format_mapping is a dict keyed by column names, [](#__codelineno-3-2)# with values as formatting functions or strings [](#__codelineno-3-3)def format_name(name): [](#__codelineno-3-4) return name.upper() [](#__codelineno-3-5) [](#__codelineno-3-6)[](#__codelineno-3-7)table = mo.ui.table( [](#__codelineno-3-8) data=[ [](#__codelineno-3-9) {"first_name": "Michael", "last_name": "Scott", "age": 45}, [](#__codelineno-3-10) {"first_name": "Dwight", "last_name": "Schrute", "age": 40}, [](#__codelineno-3-11) ], [](#__codelineno-3-12) format_mapping={ [](#__codelineno-3-13) "first_name": format_name, # Use callable to format first names [](#__codelineno-3-14) "age": "{:.1f}".format, # Use string format for age [](#__codelineno-3-15) }, [](#__codelineno-3-16) label="Format Mapping", [](#__codelineno-3-17))` Create a table with conditional cell formatting: `[](#__codelineno-4-1)import random [](#__codelineno-4-2) [](#__codelineno-4-3)[](#__codelineno-4-4)# rowId and columnName are strings. [](#__codelineno-4-5)def style_cell(_rowId, _columnName, value): [](#__codelineno-4-6) # Apply inline styling to the visible individual cells. [](#__codelineno-4-7) return { [](#__codelineno-4-8) "backgroundColor": "lightcoral" [](#__codelineno-4-9) if value < 4 [](#__codelineno-4-10) else "cornflowerblue", [](#__codelineno-4-11) "color": "white", [](#__codelineno-4-12) "fontStyle": "italic", [](#__codelineno-4-13) } [](#__codelineno-4-14) [](#__codelineno-4-15)[](#__codelineno-4-16)table = mo.ui.table( [](#__codelineno-4-17) data=[random.randint(0, 10) for x in range(200)], [](#__codelineno-4-18) style_cell=style_cell, [](#__codelineno-4-19)) [](#__codelineno-4-20)table` Create a table with per-cell hover text (plain text only): `[](#__codelineno-5-1)import random [](#__codelineno-5-2) [](#__codelineno-5-3)[](#__codelineno-5-4)# rowId and columnName are strings. [](#__codelineno-5-5)def hover_cell(rowId, columnName, value): [](#__codelineno-5-6) # Compute a short plain-text title for the visible individual cells. [](#__codelineno-5-7) return f"Row {rowId} — {columnName}: {value}" [](#__codelineno-5-8) [](#__codelineno-5-9)[](#__codelineno-5-10)table = mo.ui.table( [](#__codelineno-5-11) data=[random.randint(0, 10) for _ in range(200)], [](#__codelineno-5-12) hover_template=hover_cell, [](#__codelineno-5-13)) [](#__codelineno-5-14)table` In each case, access the table data with `table.value`. | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.table.value " value property writable (marimo.ui.table.value)")` | The selected rows, in the same format as the original data, or None if no selection. **TYPE:** `List[JSONType] | IntoDataFrame` | | `[data](#marimo.ui.table.data " data property (marimo.ui.table.data)")` | The original table data. **TYPE:** `List[JSONType] | IntoDataFrame` | | PARAMETER | DESCRIPTION | | --- | --- | | `data` | Values can be primitives (`str`, `int`, `float`, `bool`, or `None`) or marimo elements: e.g. `mo.ui.button(...)`, `mo.md(...)`, `mo.as_html(...)`, etc. Data can be passed in many ways: - as dataframes: a pandas dataframe, a polars dataframe - as rows: a list of dicts, where each dict represents a row in the table - as columns: a dict keyed by column names, where the value of each entry is a list representing a column - as a single column: a list of values **TYPE:** `List[str | int | float | bool | MIME | None] | List[Dict[str, JSONType]] | Dict[str, List[JSONType]] | IntoDataFrame` | | `pagination` | Whether to paginate; if False, all rows will be shown. Defaults to True when above 10 rows, False otherwise. **TYPE:** `bool` **DEFAULT:** `None` | | `selection` | 'single' or 'multi' to enable row selection, 'single-cell' or 'multi-cell' to enable cell selection or None to disable. Defaults to "multi". **TYPE:** `Literal['single', 'multi', 'single-cell', 'multi-cell']` **DEFAULT:** `'multi'` | | `initial_selection` | Indices of the rows you want selected by default. **TYPE:** `Union[List[int], List[tuple[str, str]]` **DEFAULT:** `None` | | `page_size` | The number of rows to show per page. Defaults to 10. **TYPE:** `int` **DEFAULT:** `None` | | `show_column_summaries` | Whether to show column summaries. Defaults to True when the table has less than 40 columns and at least 10 rows, False otherwise. If "stats", only show stats. If "chart", only show charts. **TYPE:** `bool | Literal['stats', 'chart']` **DEFAULT:** `None` | | `show_data_types` | Whether to show data types of columns in the table header. Defaults to True. **TYPE:** `bool` **DEFAULT:** `True` | | `show_download` | Whether to show the download button. Defaults to True for dataframes, False otherwise. **TYPE:** `bool` **DEFAULT:** `True` | | `format_mapping` | A mapping from column names to formatting strings or functions. **TYPE:** `Dict[str, str | Callable[..., Any]]` **DEFAULT:** `None` | | `freeze_columns_left` | List of column names to freeze on the left. **TYPE:** `Sequence[str]` **DEFAULT:** `None` | | `freeze_columns_right` | List of column names to freeze on the right. **TYPE:** `Sequence[str]` **DEFAULT:** `None` | | `text_justify_columns` | Dictionary of column names to text justification options: left, center, right. **TYPE:** `Dict[str, Literal['left', 'center', 'right']]` **DEFAULT:** `None` | | `wrapped_columns` | List of column names to wrap. **TYPE:** `List[str]` **DEFAULT:** `None` | | `header_tooltip` | Mapping from column names to tooltip text on the column header. **TYPE:** `Dict[str, str]` **DEFAULT:** `None` | | `label` | Markdown label for the element. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | `on_change` | Optional callback to run when this element's value changes. **TYPE:** `Callable[[Union[List[JSONType], Dict[str, List[JSONType]], IntoDataFrame, List[TableCell]]], None]` **DEFAULT:** `None` | | `style_cell` | A function that takes the row id, column name and value and returns a dictionary of CSS styles. **TYPE:** `Callable[[str, str, Any], Dict[str, Any]]` **DEFAULT:** `None` | | `hover_template` | Either a string template applied at the row level, or a callable that computes plain-text hover titles for individual visible cells. When a callable is provided, values are computed per page in Python and passed to the frontend; native HTML `title` is used for display. Plain text only is supported. **TYPE:** `str | Callable[[str, str, Any], str]` **DEFAULT:** `None` | | `max_columns` | Maximum number of columns to display. Defaults to the configured default\_table\_max\_columns (50 by default). Set to None to show all columns. **TYPE:** `int` **DEFAULT:** `MAX_COLUMNS_NOT_PROVIDED` | | `max_height` | Maximum height of the table body in pixels. When set, the table becomes vertically scrollable and the header will be made sticky in the UI to remain visible while scrolling. Defaults to None. **TYPE:** `int` **DEFAULT:** `None` | | `label` | A descriptive name for the table. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | ### data `property` [¶](#marimo.ui.table.data "Permanent link") Get the original table data. | RETURNS | DESCRIPTION | | --- | --- | | `TableData` | The original data passed to the table constructor, in its original format (list, dict, dataframe, etc.). **TYPE:** `TableData` | ### default\_page\_size `cached` `property` [¶](#marimo.ui.table.default_page_size "Permanent link") ### text `property` [¶](#marimo.ui.table.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.table.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.table.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.table.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.table.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.table.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.table.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### lazy `staticmethod` [¶](#marimo.ui.table.lazy "Permanent link") `[](#__codelineno-0-1)lazy( [](#__codelineno-0-2) data: IntoLazyFrame, [](#__codelineno-0-3) *, [](#__codelineno-0-4) page_size: int | None = None, [](#__codelineno-0-5) preload: bool = False, [](#__codelineno-0-6)) -> [table](#marimo.ui.table " marimo.ui.table (marimo._plugins.ui._impl.table.table)")` Create a table from a Polars LazyFrame. This won't load the data into memory until requested by the user. Once requested, only the first 10 rows will be loaded. Pagination and selection are not supported for lazy tables. | PARAMETER | DESCRIPTION | | --- | --- | | `data` | The data to display. **TYPE:** `IntoLazyFrame` | | `page_size` | The number of rows to show per page. **TYPE:** `int` **DEFAULT:** `None` | | `preload` | Whether to load the first page of data without user confirmation. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | ### left [¶](#marimo.ui.table.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.table.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.table.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Progress bar - marimo https://docs.marimo.io/examples/outputs/progress_bar Tip: paste this code into an empty cell, and the marimo editor will create cells for you `import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo import asyncio return asyncio, mo @app.cell def _(mo): rerun = mo.ui.button(label="Rerun") rerun return (rerun,) @app.cell async def _(asyncio, mo, rerun): rerun for _ in mo.status.progress_bar( range(10), title="Loading", subtitle="Please wait", show_eta=True, show_rate=True, ): await asyncio.sleep(0.5) return @app.cell def _(mo): rerun_slow = mo.ui.button(label="Rerun Slow") rerun_slow return (rerun_slow,) @app.cell async def _(asyncio, mo, rerun_slow): rerun_slow for _ in mo.status.progress_bar( range(2), title="Loading", subtitle="Please wait", show_eta=True, show_rate=True ): await asyncio.sleep(12) return if __name__ == "__main__": app.run()` Progress bar - marimo https://docs.marimo.io/examples/outputs/progress_bar/ Tip: paste this code into an empty cell, and the marimo editor will create cells for you `import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo import asyncio return asyncio, mo @app.cell def _(mo): rerun = mo.ui.button(label="Rerun") rerun return (rerun,) @app.cell async def _(asyncio, mo, rerun): rerun for _ in mo.status.progress_bar( range(10), title="Loading", subtitle="Please wait", show_eta=True, show_rate=True, ): await asyncio.sleep(0.5) return @app.cell def _(mo): rerun_slow = mo.ui.button(label="Rerun Slow") rerun_slow return (rerun_slow,) @app.cell async def _(asyncio, mo, rerun_slow): rerun_slow for _ in mo.status.progress_bar( range(2), title="Loading", subtitle="Please wait", show_eta=True, show_rate=True ): await asyncio.sleep(12) return if __name__ == "__main__": app.run()` Plotting - marimo https://docs.marimo.io/api/plotting#reactive-charts-with-altair marimo supports most major plotting libraries, including Matplotlib, Seaborn, Plotly, and Altair. Just import your plotting library of choice and use it as you normally would. For more information about plotting, see the [plotting guide](https://docs.marimo.io/guides/working_with_data/plotting/). Reactive plots with matplotlib[¶](#reactive-plots-with-matplotlib "Permanent link") ----------------------------------------------------------------------------------- marimo.ui.matplotlib [¶](#marimo.ui.matplotlib "Permanent link") ---------------------------------------------------------------- `[](#__codelineno-0-1)matplotlib(axes: Axes, *, debounce: bool = False)` Bases: `UIElement[dict[str, JSONType], MatplotlibSelection]` Make reactive selections on matplotlib plots. Use `mo.ui.matplotlib` to make matplotlib plots interactive: draw a box selection or a freehand lasso selection on the frontend, then use the selection geometry in Python to filter your data. The figure is rendered as a static image with an interactive selection overlay: * click and drag for box selection; * hold the `Shift` key and drag for lasso selection. Example `[](#__codelineno-0-1)import matplotlib.pyplot as plt [](#__codelineno-0-2)import marimo as mo [](#__codelineno-0-3)import numpy as np [](#__codelineno-0-4)[](#__codelineno-0-5)x = np.arange(5) [](#__codelineno-0-6)y = x**2 [](#__codelineno-0-7)plt.scatter(x=x, y=y) [](#__codelineno-0-8)ax = mo.ui.matplotlib(plt.gca()) [](#__codelineno-0-9)ax` `[](#__codelineno-1-1)# Filter data using the selection [](#__codelineno-1-2)mask = ax.value.get_mask(x, y) [](#__codelineno-1-3)selected_x, selected_y = x[mask], y[mask]` `[](#__codelineno-2-1)# Check if anything is selected [](#__codelineno-2-2)if ax.value: [](#__codelineno-2-3) print("Data has been selected")` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.matplotlib.value " value property writable (marimo.ui.matplotlib.value)")` | The selected data, with `get_mask(x, y)` returning a mask array corresponding to the selection. **TYPE:** `T` | | PARAMETER | DESCRIPTION | | --- | --- | | `axes` | A matplotlib `Axes` object. The full figure is rendered, but selections map to this axes' coordinate space. **TYPE:** `Axes` | | `debounce` | If `True`, the selection is only sent to Python on mouse-up. If `False` (the default), it streams while dragging. **TYPE:** `bool` **DEFAULT:** `False` | ### axes `property` [¶](#marimo.ui.matplotlib.axes "Permanent link") The associated matplotlib Axes object. ### name `class-attribute` `instance-attribute` [¶](#marimo.ui.matplotlib.name "Permanent link") `[](#__codelineno-0-1)name: Final[str] = 'marimo-matplotlib'` ### text `property` [¶](#marimo.ui.matplotlib.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.matplotlib.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.matplotlib.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.matplotlib.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.matplotlib.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.matplotlib.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.matplotlib.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### left [¶](#marimo.ui.matplotlib.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.matplotlib.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.matplotlib.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Reactive charts with Altair[¶](#reactive-charts-with-altair "Permanent link") ----------------------------------------------------------------------------- ### Disabling automatic selection[¶](#disabling-automatic-selection "Permanent link") marimo automatically adds a default selection based on the mark type, however, you may want to customize the selection behavior of your Altair chart. You can do this by setting `chart_selection` and `legend_selection` to `False`, and using `.add_params` directly on your Altair chart. `[](#__codelineno-1-1)# Create an interval selection [](#__codelineno-1-2)brush = alt.selection_interval(encodings=["x"]) [](#__codelineno-1-3)[](#__codelineno-1-4)_chart = ( [](#__codelineno-1-5) alt.Chart(traces, height=150) [](#__codelineno-1-6) .mark_line() [](#__codelineno-1-7) .encode(x="index:Q", y="value:Q", color="traces:N") [](#__codelineno-1-8) .add_params(brush) # add the selection to the chart [](#__codelineno-1-9)) [](#__codelineno-1-10)[](#__codelineno-1-11)chart = mo.ui.altair_chart( [](#__codelineno-1-12) _chart, [](#__codelineno-1-13) # disable automatic selection [](#__codelineno-1-14) chart_selection=False, [](#__codelineno-1-15) legend_selection=False [](#__codelineno-1-16)) [](#__codelineno-1-17)chart # You can now access chart.value to get the selected data` marimo.ui.altair\_chart [¶](#marimo.ui.altair_chart "Permanent link") --------------------------------------------------------------------- `[](#__codelineno-0-1)altair_chart( [](#__codelineno-0-2) chart: AltairChartType, [](#__codelineno-0-3) chart_selection: Literal["point"] [](#__codelineno-0-4) | Literal["interval"] [](#__codelineno-0-5) | bool = True, [](#__codelineno-0-6) legend_selection: list[str] | bool = True, [](#__codelineno-0-7) *, [](#__codelineno-0-8) label: str = "", [](#__codelineno-0-9) on_change: Callable[[ChartDataType], None] [](#__codelineno-0-10) | None = None, [](#__codelineno-0-11))` Bases: `UIElement[ChartSelection, ChartDataType]` Make reactive charts with Altair. Use `mo.ui.altair_chart` to make Altair charts reactive: select chart data with your cursor on the frontend, get them as a dataframe in Python! Supports polars, pandas, and arrow DataFrames. Examples: `[](#__codelineno-0-1)import altair as alt [](#__codelineno-0-2)import marimo as mo [](#__codelineno-0-3)from vega_datasets import data [](#__codelineno-0-4)[](#__codelineno-0-5)chart = ( [](#__codelineno-0-6) alt.Chart(data.cars()) [](#__codelineno-0-7) .mark_point() [](#__codelineno-0-8) .encode( [](#__codelineno-0-9) x="Horsepower", [](#__codelineno-0-10) y="Miles_per_Gallon", [](#__codelineno-0-11) color="Origin", [](#__codelineno-0-12) ) [](#__codelineno-0-13)) [](#__codelineno-0-14)[](#__codelineno-0-15)chart = mo.ui.altair_chart(chart)` `[](#__codelineno-1-1)# View the chart and selected data as a dataframe [](#__codelineno-1-2)mo.hstack([chart, chart.value])` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.altair_chart.value " value property writable (marimo.ui.altair_chart.value)")` | A dataframe of the plot data filtered by the selections. **TYPE:** `ChartDataType` | | `[dataframe](#marimo.ui.altair_chart.dataframe " dataframe instance-attribute (marimo.ui.altair_chart.dataframe)")` | A dataframe of the unfiltered chart data. **TYPE:** `ChartDataType` | | `[selections](#marimo.ui.altair_chart.selections " selections property (marimo.ui.altair_chart.selections)")` | The selection of the chart; this may be an interval along the name of an axis or a selection of points. **TYPE:** `ChartSelection` | | PARAMETER | DESCRIPTION | | --- | --- | | `chart` | An Altair Chart object. **TYPE:** `Chart` | | `chart_selection` | Selection type, "point", "interval", or a bool. Defaults to True which will automatically detect the best selection type. This is ignored if the chart already has a point/interval selection param. **TYPE:** `Literal['point'] | Literal['interval'] | bool` **DEFAULT:** `True` | | `legend_selection` | List of legend fields (columns) for which to enable selection, True to enable selection for all fields, or False to disable selection entirely. This is ignored if the chart already has a legend selection param. Defaults to True. **TYPE:** `list[str] | bool` **DEFAULT:** `True` | | `label` | Markdown label for the element. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[ChartDataType], None] | None` **DEFAULT:** `None` | ### dataframe `instance-attribute` [¶](#marimo.ui.altair_chart.dataframe "Permanent link") `[](#__codelineno-0-1)dataframe: ChartDataType | None = _get_dataframe_from_chart( [](#__codelineno-0-2) chart [](#__codelineno-0-3))` ### name `class-attribute` `instance-attribute` [¶](#marimo.ui.altair_chart.name "Permanent link") `[](#__codelineno-0-1)name: Final[str] = 'marimo-vega'` ### selections `property` [¶](#marimo.ui.altair_chart.selections "Permanent link") `[](#__codelineno-0-1)selections: ChartSelection` ### text `property` [¶](#marimo.ui.altair_chart.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.altair_chart.value "Permanent link") ### apply\_selection [¶](#marimo.ui.altair_chart.apply_selection "Permanent link") `[](#__codelineno-0-1)apply_selection(df: ChartDataType) -> ChartDataType` Apply the selection to a DataFrame. This method is useful when you have a layered chart and you want to apply the selection to a DataFrame. | PARAMETER | DESCRIPTION | | --- | --- | | `df` | A DataFrame to apply the selection to. **TYPE:** `ChartDataType` | | RETURNS | DESCRIPTION | | --- | --- | | `ChartDataType` | A DataFrame of the plot data filtered by the selections. **TYPE:** `ChartDataType` | Examples: `[](#__codelineno-0-1)import altair as alt [](#__codelineno-0-2)import marimo as mo [](#__codelineno-0-3)from vega_datasets import data [](#__codelineno-0-4)[](#__codelineno-0-5)cars = data.cars() [](#__codelineno-0-6)[](#__codelineno-0-7)_chart = ( [](#__codelineno-0-8) alt.Chart(cars) [](#__codelineno-0-9) .mark_point() [](#__codelineno-0-10) .encode( [](#__codelineno-0-11) x="Horsepower", [](#__codelineno-0-12) y="Miles_per_Gallon", [](#__codelineno-0-13) color="Origin", [](#__codelineno-0-14) ) [](#__codelineno-0-15)) [](#__codelineno-0-16)[](#__codelineno-0-17)chart = mo.ui.altair_chart(_chart) [](#__codelineno-0-18)chart [](#__codelineno-0-19)[](#__codelineno-0-20)# In another cell [](#__codelineno-0-21)selected_df = chart.apply_selection(cars)` ### batch [¶](#marimo.ui.altair_chart.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.altair_chart.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.altair_chart.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.altair_chart.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.altair_chart.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### left [¶](#marimo.ui.altair_chart.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.altair_chart.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.altair_chart.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | ### Performance and Data Transformers[¶](#performance-and-data-transformers "Permanent link") Altair has a concept of [data](https://altair-viz.github.io/user_guide/data_transformers.html) transformers, which can be used to improve performance. Some examples are: * pandas Dataframe has to be sanitized and serialized to JSON; * the rows of a Dataframe might need to be sampled or limited to a maximum number; * the Dataframe might be written to a `.csv` or `.json` file for performance reasons. By default, Altair uses the `default` data transformer, which is the slowest in marimo. It is limited to 5000 rows (although we increase this to `20_000` rows as marimo can handle this). This includes the data inside the HTML that is being sent over the network, which can also be limited by marimo's maximum message size. It is recommended to use the `marimo_csv` data transformer, which is the most performant and can handle the largest datasets: it converts the data to a CSV file which is smaller and can be sent over the network. This can handle up to +400,000 rows with no issues. When using `mo.ui.altair_chart`, we automatically set the data transformer to `marimo_csv` for you. If you are using Altair directly, you can set the data transformer using the following code: `[](#__codelineno-2-1)import altair as alt [](#__codelineno-2-2)alt.data_transformers.enable('marimo_csv')` Reactive plots with Plotly[¶](#reactive-plots-with-plotly "Permanent link") --------------------------------------------------------------------------- Supported charts marimo can render any Plotly plot, but [`mo.ui.plotly`](#marimo.ui.plotly " marimo.ui.plotly") only supports reactive selections for scatter/scattergl plots, pure line charts, bar charts, histograms, heatmaps, treemaps, and sunburst charts. If you require other kinds of selection, please [file an issue](https://github.com/marimo-team/marimo/issues). marimo.ui.plotly [¶](#marimo.ui.plotly "Permanent link") -------------------------------------------------------- `[](#__codelineno-0-1)plotly( [](#__codelineno-0-2) figure: Figure, [](#__codelineno-0-3) config: dict[str, Any] | None = None, [](#__codelineno-0-4) renderer_name: str | None = None, [](#__codelineno-0-5) *, [](#__codelineno-0-6) label: str = "", [](#__codelineno-0-7) on_change: Callable[[JSONType], None] | None = None, [](#__codelineno-0-8))` Bases: `UIElement[PlotlySelection, list[dict[str, Any]]]` Make reactive plots with Plotly. Use `mo.ui.plotly` to make plotly plots reactive: select data with your cursor on the frontend, get them as a list of dicts in Python! This function supports scatter plots, scattergl plots, line charts, area charts, bar charts, histograms, treemap charts, sunburst charts, and heatmaps. Examples: `[](#__codelineno-0-1)import plotly.express as px [](#__codelineno-0-2)import marimo as mo [](#__codelineno-0-3)from vega_datasets import data [](#__codelineno-0-4)[](#__codelineno-0-5)_plot = px.scatter( [](#__codelineno-0-6) data.cars(), x="Horsepower", y="Miles_per_Gallon", color="Origin" [](#__codelineno-0-7)) [](#__codelineno-0-8)[](#__codelineno-0-9)plot = mo.ui.plotly(_plot)` `[](#__codelineno-1-1)# View the plot and selected data [](#__codelineno-1-2)mo.hstack([plot, plot.value])` Or with custom configuration: `[](#__codelineno-2-1)plot = mo.ui.plotly( [](#__codelineno-2-2) _plot, [](#__codelineno-2-3) config={"staticPlot": True}, [](#__codelineno-2-4))` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.plotly.value " value property writable (marimo.ui.plotly.value)")` | A dict of the plot data. **TYPE:** `Dict[str, Any]` | | `[ranges](#marimo.ui.plotly.ranges " ranges property (marimo.ui.plotly.ranges)")` | The selection of the plot; this may be an interval along the name of an axis. **TYPE:** `Dict[str, List[float]]` | | `[points](#marimo.ui.plotly.points " points property (marimo.ui.plotly.points)")` | The selected points data. **TYPE:** `List[Dict[str, Any]]` | | `[indices](#marimo.ui.plotly.indices " indices property (marimo.ui.plotly.indices)")` | The indices of selected points. **TYPE:** `List[int]` | | PARAMETER | DESCRIPTION | | --- | --- | | `figure` | A plotly Figure object. **TYPE:** `Figure` | | `config` | Configuration for the plot. This is a dictionary that is passed directly to plotly. See the plotly documentation for more information: [https://plotly.com/javascript/configuration-options/](https://plotly.com/javascript/configuration-options/) This takes precedence over the default configuration of the renderer. Defaults to None. **TYPE:** `Dict[str, Any] | None` **DEFAULT:** `None` | | `renderer_name` | Renderer to use for the plot. If this is not provided, the default renderer (`pio.renderers.default`) is used. Defaults to None. **TYPE:** `str | None` **DEFAULT:** `None` | | `label` | Markdown label for the element. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | `on_change` | Callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[JSONType], None] | None` **DEFAULT:** `None` | ### indices `property` [¶](#marimo.ui.plotly.indices "Permanent link") Get the indices of selected points in the plot. | RETURNS | DESCRIPTION | | --- | --- | | `list[int]` | List\[int\]: A list of indices corresponding to the selected points. Returns an empty list if no points are selected. | ### name `class-attribute` `instance-attribute` [¶](#marimo.ui.plotly.name "Permanent link") `[](#__codelineno-0-1)name: Final[str] = 'marimo-plotly'` ### points `property` [¶](#marimo.ui.plotly.points "Permanent link") `[](#__codelineno-0-1)points: list[dict[str, Any]]` Get the selected points data from the plot. | RETURNS | DESCRIPTION | | --- | --- | | `list[dict[str, Any]]` | List\[Dict\[str, Any\]\]: A list of dictionaries containing the data for each selected point. Returns an empty list if no points are selected. | ### ranges `property` [¶](#marimo.ui.plotly.ranges "Permanent link") `[](#__codelineno-0-1)ranges: dict[str, list[float]]` Get the range selection of the plot. | RETURNS | DESCRIPTION | | --- | --- | | `dict[str, list[float]]` | Dict\[str, List\[float\]\]: A dictionary mapping field names to their selected ranges, where each range is a list of \[min, max\] values. Returns an empty dict if no range selection exists. | ### text `property` [¶](#marimo.ui.plotly.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.plotly.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.plotly.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/inputs/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.plotly.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.plotly.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.plotly.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/inputs/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.plotly.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### left [¶](#marimo.ui.plotly.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.plotly.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.plotly.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | Interactive matplotlib[¶](#interactive-matplotlib "Permanent link") ------------------------------------------------------------------- marimo.mpl.interactive [¶](#marimo.mpl.interactive "Permanent link") -------------------------------------------------------------------- `[](#__codelineno-0-1)interactive(figure: Figure | SubFigure | Axes) -> [Html](https://docs.marimo.io/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Render a matplotlib figure using an interactive viewer. The interactive viewer allows you to pan, zoom, and see plot coordinates on mouse hover. Example `[](#__codelineno-0-1)plt.plot([1, 2]) [](#__codelineno-0-2)# plt.gcf() gets the current figure [](#__codelineno-0-3)mo.mpl.interactive(plt.gcf())` | PARAMETER | DESCRIPTION | | --- | --- | | `figure` | A matplotlib `Figure` or `Axes` object. **TYPE:** `matplotlib Figure or Axes` | | RETURNS | DESCRIPTION | | --- | --- | | `Html` | An interactive matplotlib figure as an `Html` object. **TYPE:** `[Html](https://docs.marimo.io/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | Source code in `marimo/_plugins/stateless/mpl/_mpl.py`
@mddoc
def interactive(figure: Union[Figure, SubFigure, Axes]) -> Html:
    """Render a matplotlib figure using an interactive viewer.

    The interactive viewer allows you to pan, zoom, and see plot coordinates
    on mouse hover.

    Example:
        ```python
        plt.plot([1, 2])
        # plt.gcf() gets the current figure
        mo.mpl.interactive(plt.gcf())
        ```

    Args:
        figure (matplotlib Figure or Axes): A matplotlib `Figure` or `Axes` object.

    Returns:
        Html: An interactive matplotlib figure as an `Html` object.
    """
    # No top-level imports of matplotlib, since it isn't a required
    # dependency
    from matplotlib.axes import Axes

    if isinstance(figure, Axes):
        maybe_figure = figure.get_figure()
        assert maybe_figure is not None, "Axes object does not have a Figure"
        figure = maybe_figure

    ctx = get_context()
    if not isinstance(ctx, KernelRuntimeContext):
        return NonInteractiveMplHtml(figure)

    # When virtual files are not supported (e.g., during HTML export),
    # fall back to static PNG instead of interactive plot
    if not ctx.virtual_files_supported:
        return NonInteractiveMplHtml(figure)

    from marimo._plugins.ui._impl.from_mpl_interactive import mpl_interactive

    return mpl_interactive(figure)
Leafmap[¶](#leafmap "Permanent link") ------------------------------------- marimo supports rendering [Leafmap](https://leafmap.org/) maps using the `folium` and `plotly` backends. Other plotting libraries[¶](#other-plotting-libraries "Permanent link") ----------------------------------------------------------------------- You can use all the popular plotting libraries with marimo, such as: * [Matplotlib](https://matplotlib.org/) * [Plotly](https://plotly.com/) * [Seaborn](https://seaborn.pydata.org/) * [Bokeh](https://bokeh.org/) * [Altair](https://altair-viz.github.io/) * [HoloViews](http://holoviews.org/) * [hvPlot](https://hvplot.holoviz.org/) * [Leafmap](https://leafmap.org/) * [Pygwalker](https://kanaries.net/pygwalker)
Spinner - marimo https://docs.marimo.io/examples/outputs/spinner/ Tip: paste this code into an empty cell, and the marimo editor will create cells for you `import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(mo): rerun = mo.ui.button(label="Rerun") rerun return (rerun,) @app.cell async def _(mo, rerun): import asyncio rerun with mo.status.spinner(title="Loading...") as _spinner: await asyncio.sleep(1) _spinner.update("Almost done") await asyncio.sleep(1) _spinner.update("Done") return if __name__ == "__main__": app.run()` Spinner - marimo https://docs.marimo.io/examples/outputs/spinner Tip: paste this code into an empty cell, and the marimo editor will create cells for you `import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(mo): rerun = mo.ui.button(label="Rerun") rerun return (rerun,) @app.cell async def _(mo, rerun): import asyncio rerun with mo.status.spinner(title="Loading...") as _spinner: await asyncio.sleep(1) _spinner.update("Almost done") await asyncio.sleep(1) _spinner.update("Done") return if __name__ == "__main__": app.run()` Horizontal and vertical stacking - marimo https://docs.marimo.io/examples/outputs/stacks/ Tip: paste this code into an empty cell, and the marimo editor will create cells for you `import marimo __generated_with = "0.19.11" app = marimo.App() @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(mo): t = mo.ui.date() n = mo.ui.slider(1, 10) return n, t @app.cell def _(mo, n, t): mo.hstack([t, n], justify="start") return @app.cell def _(mo, n, t): mo.vstack([t, n]) return @app.cell def _(mo): mo.hstack( [ mo.stat(value=1, bordered=True), mo.stat(value=2, bordered=True), mo.stat(value=3, bordered=True), ], widths="equal", ) return @app.cell def _(mo): text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Name faucibus risus in feugiat pharetra. Praesent vel ex nibh. " q = mo.vstack([mo.md(text)] * 5) s = mo.vstack([mo.md(str(0.5))] * 5, align="end", justify="space-between") mo.hstack([q, s], widths=[5, 1]) return if __name__ == "__main__": app.run()` Accordion - marimo https://docs.marimo.io/api/layouts/accordion Source code for `examples/outputs/accordion.py` Tip: paste this code into an empty cell, and the marimo editor will create cells for you `import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(mo): mo.accordion( { "Door 1": mo.md("Nothing!"), "Door 2": mo.md("Nothing!"), "Door 3": mo.md( "![goat](https://images.unsplash.com/photo-1524024973431-2ad916746881)" ), } ) return if __name__ == "__main__": app.run()` marimo.accordion [¶](#marimo.accordion "Permanent link") -------------------------------------------------------- `[](#__codelineno-0-1)accordion( [](#__codelineno-0-2) items: dict[str, object], [](#__codelineno-0-3) multiple: bool = False, [](#__codelineno-0-4) lazy: bool = False, [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Accordion of one or more items. | PARAMETER | DESCRIPTION | | --- | --- | | `items` | a dictionary of item names to item content; strings are interpreted as markdown **TYPE:** `dict[str, object]` | | `multiple` | whether to allow multiple items to be open simultaneously **TYPE:** `bool` **DEFAULT:** `False` | | `lazy` | a boolean, whether to lazily load the accordion content. This is a convenience that wraps each accordion in a `mo.lazy` component. **TYPE:** `bool` **DEFAULT:** `False` | | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | Example `[](#__codelineno-0-1)mo.accordion( [](#__codelineno-0-2) {"Tip": "Use accordions to let users reveal and hide content."} [](#__codelineno-0-3))` Accordion content can be lazily loaded: `[](#__codelineno-1-1)mo.accordion({"View total": expensive_item}, lazy=True)` where `expensive_item` is the item to render, or a callable that returns the item to render. Tabs - marimo https://docs.marimo.io/api/inputs/tabs Source code for `examples/ui/tabs.py` Tip: paste this code into an empty cell, and the marimo editor will create cells for you `import marimo __generated_with = "0.19.7" app = marimo.App() @app.cell def _(): import marimo as mo return (mo,) @app.cell def _(mo): tabs = mo.ui.tabs({ "Bob says": mo.md("Hello, Alice! 👋"), "Alice says": mo.md("Hello, Bob! 👋") }) tabs return (tabs,) @app.cell def _(tabs): tabs.value return if __name__ == "__main__": app.run()` marimo.ui.tabs [¶](#marimo.ui.tabs "Permanent link") ---------------------------------------------------- `[](#__codelineno-0-1)tabs( [](#__codelineno-0-2) tabs: dict[str, object], [](#__codelineno-0-3) value: str | None = None, [](#__codelineno-0-4) lazy: bool = False, [](#__codelineno-0-5) *, [](#__codelineno-0-6) label: str = "", [](#__codelineno-0-7) on_change: Callable[[str], None] | None = None, [](#__codelineno-0-8))` Bases: `UIElement[str, str]` Display objects in a tabbed view. Examples: Show content in tabs: `[](#__codelineno-0-1)tab1 = mo.vstack([mo.ui.slider(1, 10), mo.ui.text(), mo.ui.date()]) [](#__codelineno-0-2)[](#__codelineno-0-3)tab2 = mo.md("You can show arbitrary content in a tab.") [](#__codelineno-0-4)[](#__codelineno-0-5)tabs = mo.ui.tabs({"Heading 1": tab1, "Heading 2": tab2})` Control which tab is selected: `[](#__codelineno-1-1)tabs = mo.ui.tabs( [](#__codelineno-1-2) {"Heading 1": tab1, "Heading 2": tab2}, value="Heading 2" [](#__codelineno-1-3))` Tab content can be lazily loaded: `[](#__codelineno-2-1)tabs = mo.ui.tabs( [](#__codelineno-2-2) {"Heading 1": tab1, "Heading 2": expensive_component}, lazy=True [](#__codelineno-2-3))` | ATTRIBUTE | DESCRIPTION | | --- | --- | | `[value](#marimo.ui.tabs.value " value property writable (marimo.ui.tabs.value)")` | The name of the selected tab. **TYPE:** `str` | | PARAMETER | DESCRIPTION | | --- | --- | | `tabs` | A dictionary of tab names to tab content; strings are interpreted as markdown. **TYPE:** `dict[str, object]` | | `value` | The name of the tab to open. Defaults to the first tab. **TYPE:** `str` **DEFAULT:** `None` | | `lazy` | Whether to lazily load the tab content. This is a convenience that wraps each tab in a `mo.lazy` component. Defaults to False. **TYPE:** `bool` **DEFAULT:** `False` | | `label` | A descriptive name for the tab. Defaults to "". **TYPE:** `str` **DEFAULT:** `''` | | `on_change` | Optional callback to run when this element's value changes. **TYPE:** `Callable[[dict[str, object]], None]` **DEFAULT:** `None` | ### text `property` [¶](#marimo.ui.tabs.text "Permanent link") A string of HTML representing this element. ### value `property` `writable` [¶](#marimo.ui.tabs.value "Permanent link") The element's current value. ### batch [¶](#marimo.ui.tabs.batch "Permanent link") `[](#__codelineno-0-1)batch(**elements: UIElement[JSONType, object]) -> [batch](https://docs.marimo.io/api/batch/#marimo.ui.batch " marimo.ui.batch (marimo._plugins.ui._impl.batch.batch)")` Convert an HTML object with templated text into a UI element. This method lets you create custom UI elements that are represented by arbitrary HTML. Example `[](#__codelineno-0-1)user_info = mo.md( [](#__codelineno-0-2) ''' [](#__codelineno-0-3) - What's your name?: {name} [](#__codelineno-0-4) - When were you born?: {birthday} [](#__codelineno-0-5) ''' [](#__codelineno-0-6)).batch(name=mo.ui.text(), birthday=mo.ui.date())` In this example, `user_info` is a UI Element whose output is markdown and whose value is a dict with keys `'name'` and '`birthday`' (and values equal to the values of their corresponding elements). | PARAMETER | DESCRIPTION | | --- | --- | | `elements` | the UI elements to interpolate into the HTML template. **TYPE:** `UIElement[JSONType, object]` **DEFAULT:** `{}` | ### callout [¶](#marimo.ui.tabs.callout "Permanent link") `[](#__codelineno-0-1)callout( [](#__codelineno-0-2) kind: Literal[ [](#__codelineno-0-3) "neutral", "danger", "warn", "success", "info" [](#__codelineno-0-4) ] = "neutral", [](#__codelineno-0-5)) -> [Html](https://docs.marimo.io/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Create a callout containing this HTML element. A callout wraps your HTML element in a raised box, emphasizing its importance. You can style the callout for different situations with the `kind` argument. Examples: `[](#__codelineno-0-1)mo.md("Hooray, you did it!").callout(kind="success")` `[](#__codelineno-1-1)mo.md("It's dangerous to go alone!").callout(kind="warn")` ### center [¶](#marimo.ui.tabs.center "Permanent link") Center an item. Example `[](#__codelineno-0-1)mo.md("# Hello, world").center()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### form [¶](#marimo.ui.tabs.form "Permanent link") `[](#__codelineno-0-1)form( [](#__codelineno-0-2) label: str = "", [](#__codelineno-0-3) *, [](#__codelineno-0-4) bordered: bool = True, [](#__codelineno-0-5) loading: bool = False, [](#__codelineno-0-6) submit_button_label: str = "Submit", [](#__codelineno-0-7) submit_button_tooltip: str | None = None, [](#__codelineno-0-8) submit_button_disabled: bool = False, [](#__codelineno-0-9) clear_on_submit: bool = False, [](#__codelineno-0-10) show_clear_button: bool = False, [](#__codelineno-0-11) clear_button_label: str = "Clear", [](#__codelineno-0-12) clear_button_tooltip: str | None = None, [](#__codelineno-0-13) validate: Callable[[Optional[JSONType]], str | None] [](#__codelineno-0-14) | None = None, [](#__codelineno-0-15) on_change: Callable[[Optional[T]], None] | None = None, [](#__codelineno-0-16)) -> [form](https://docs.marimo.io/api/form/#marimo.ui.form " marimo.ui.form (marimo._plugins.ui._impl.input.form)")[S, T]` Create a submittable form out of this `UIElement`. Creates a form that gates submission of a `UIElement`'s value until a submit button is clicked. The form's value is the value of the underlying element from the last submission. Examples: Convert any `UIElement` into a form: `[](#__codelineno-0-1)prompt = mo.ui.text_area().form()` Combine with `HTML.batch` to create a form made out of multiple `UIElements`: `[](#__codelineno-1-1)form = ( [](#__codelineno-1-2) mo.md( [](#__codelineno-1-3) ''' [](#__codelineno-1-4) **Enter your prompt.** [](#__codelineno-1-5) [](#__codelineno-1-6) {prompt} [](#__codelineno-1-7) [](#__codelineno-1-8) **Choose a random seed.** [](#__codelineno-1-9) [](#__codelineno-1-10) {seed} [](#__codelineno-1-11) ''' [](#__codelineno-1-12) ) [](#__codelineno-1-13) .batch( [](#__codelineno-1-14) prompt=mo.ui.text_area(), [](#__codelineno-1-15) seed=mo.ui.number(), [](#__codelineno-1-16) ) [](#__codelineno-1-17) .form() [](#__codelineno-1-18))` | PARAMETER | DESCRIPTION | | --- | --- | | `label` | A text label for the form. **TYPE:** `str` **DEFAULT:** `''` | | `bordered` | Whether the form should have a border. **TYPE:** `bool` **DEFAULT:** `True` | | `loading` | Whether the form should be in a loading state. **TYPE:** `bool` **DEFAULT:** `False` | | `submit_button_label` | The label of the submit button. **TYPE:** `str` **DEFAULT:** `'Submit'` | | `submit_button_tooltip` | The tooltip of the submit button. **TYPE:** `str | None` **DEFAULT:** `None` | | `submit_button_disabled` | Whether the submit button should be disabled. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_on_submit` | Whether the form should clear its contents after submitting. **TYPE:** `bool` **DEFAULT:** `False` | | `show_clear_button` | Whether the form should show a clear button. **TYPE:** `bool` **DEFAULT:** `False` | | `clear_button_label` | The label of the clear button. **TYPE:** `str` **DEFAULT:** `'Clear'` | | `clear_button_tooltip` | The tooltip of the clear button. **TYPE:** `str | None` **DEFAULT:** `None` | | `validate` | A function that takes the form's value and returns an error message if invalid, or `None` if valid. **TYPE:** `Callable[[Optional[JSONType]], str | None] | None` **DEFAULT:** `None` | | `on_change` | Optional callback to run when this element's value changes. Defaults to None. **TYPE:** `Callable[[Optional[T]], None] | None` **DEFAULT:** `None` | ### from\_args `classmethod` [¶](#marimo.ui.tabs.from_args "Permanent link") `[](#__codelineno-0-1)from_args( [](#__codelineno-0-2) data: dict[str, int], [](#__codelineno-0-3) args: InitializationArgs[S, T], [](#__codelineno-0-4) memo: dict[int, Any] | None = None, [](#__codelineno-0-5) basis: UIElement[S, T] | None = None, [](#__codelineno-0-6)) -> UIElement[S, T]` ### left [¶](#marimo.ui.tabs.left "Permanent link") Left-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").left()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### right [¶](#marimo.ui.tabs.right "Permanent link") Right-justify. Example `[](#__codelineno-0-1)mo.md("# Hello, world").right()` | RETURNS | DESCRIPTION | | --- | --- | | `[Html](https://docs.marimo.io/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` | An `Html` object. | ### style [¶](#marimo.ui.tabs.style "Permanent link") `[](#__codelineno-0-1)style( [](#__codelineno-0-2) style: dict[str, Any] | None = None, **kwargs: Any [](#__codelineno-0-3)) -> [Html](https://docs.marimo.io/html/#marimo.Html " marimo.Html dataclass (marimo._output.hypertext.Html)")` Wrap an object in a styled container. Example `[](#__codelineno-0-1)mo.md("...").style({"max-height": "300px", "overflow": "auto"}) [](#__codelineno-0-2)mo.md("...").style(max_height="300px", overflow="auto")` | PARAMETER | DESCRIPTION | | --- | --- | | `style` | an optional dict of CSS styles, keyed by property name **TYPE:** `dict[str, Any] | None` **DEFAULT:** `None` | | `**kwargs` | CSS styles as keyword arguments **TYPE:** `Any` **DEFAULT:** `{}` | marimo islands 🏝️ - marimo https://docs.marimo.io/guides/island_example/ Preview Islands are an early feature. While the API likely won't change, there are some improvements we'd like to make before we consider them stable. Please let us know on [GitHub](https://github.com/marimo-team/marimo/issues) if you run into any issues or have any feedback! > This content below is powered by marimo's reactive runtime. It will become interactive after initializing the marimo runtime. * * * Hello, islands! 🏝️🏝️ * * * See the HTML `[](#__codelineno-0-1) [](#__codelineno-0-2) [](#__codelineno-0-3) [](#__codelineno-0-4) [](#__codelineno-0-5) [](#__codelineno-0-6) [](#__codelineno-0-7) [](#__codelineno-0-8) [](#__codelineno-0-19) [](#__codelineno-0-20) [](#__codelineno-0-21) [](#__codelineno-0-22) [](#__codelineno-0-23) [](#__codelineno-0-24) [](#__codelineno-0-25) Hello, islands! 🏝️🏝️ [](#__codelineno-0-26) [](#__codelineno-0-27) [](#__codelineno-0-28) [](#__codelineno-0-35) [](#__codelineno-0-36)` Running cells - marimo https://docs.marimo.io/guides/reactivity marimo _reacts_ to your code changes: run a cell, and all other cells that refer to the variables it defines are automatically run with the latest data. This keeps your code and outputs consistent, and eliminates bugs before they happen. Why run cells reactively? marimo's "reactive" execution model makes your notebooks more reproducible by eliminating hidden state and providing a deterministic execution order. It also powers marimo's support for [interactive elements](https://docs.marimo.io/interactivity/), for running as apps, and executing as scripts. How marimo runs cells is one of the biggest differences between marimo and traditional notebooks like Jupyter. Learn more at our [FAQ](https://docs.marimo.io/faq/#faq-jupyter). Working with expensive notebooks marimo provides tools for working with expensive notebooks, in which cells might take a long time to run or have side-effects. * The [runtime can be configured](https://docs.marimo.io/configuration/runtime_configuration/) to be **lazy** instead of automatic, marking cells as stale instead of running them. * Use [`mo.stop`](https://docs.marimo.io/api/control_flow/#marimo.stop " marimo.stop") to conditionally stop execution at runtime. See [the expensive notebooks guide](https://docs.marimo.io/expensive_notebooks/) for more tips. How marimo runs cells[¶](#how-marimo-runs-cells "Permanent link") ----------------------------------------------------------------- marimo statically analyzes each cell (i.e., without running it) to determine its * references, the global variables it reads but doesn't define; * definitions, the global variables it defines. It then forms a directed acyclic graph (DAG) on cells, with an edge from one cell to another if the latter references any of the definitions of the former. When a cell is run, its descendants are marked for execution. Runtime Rule When a cell is run, marimo automatically runs all other cells that **reference** any of the global variables it **defines**. marimo [does not track mutations](#variable-mutations-are-not-tracked) to variables, nor assignments to attributes. That means that if you assign an attribute like `foo.bar = 10`, other cells referencing `foo.bar` will _not_ be run. ### Execution order[¶](#execution-order "Permanent link") The order cells are executed in is determined by the relationships between cells and their variables, not by the order of cells on the page (similar to a spreadsheet). This lets you organize your code in whatever way makes the most sense to you. For example, you can put helper functions at the bottom of your notebook. ### Deleting a cell deletes its variables[¶](#deleting-a-cell-deletes-its-variables "Permanent link") In marimo, _deleting a cell deletes its global variables from program memory_. Cells that previously referenced these variables are automatically re-run and invalidated (or marked as stale, depending on your [runtime configuration](https://docs.marimo.io/configuration/runtime_configuration/)). In this way, marimo eliminates a common cause of bugs in traditional notebooks like Jupyter. ### Variable mutations are not tracked[¶](#variable-mutations-are-not-tracked "Permanent link") marimo does not track mutations to objects, _e.g._, mutations like `my_list.append(42)` or `my_object.value = 42` don't trigger reactive re-runs of other cells. **Avoid defining a variable in one cell and mutating it in another**. Why not track mutations? Tracking mutations reliably is impossible in Python. Reacting to mutations could result in surprising re-runs of notebook cells. If you need to mutate a variable (such as adding a new column to a dataframe), you should perform the mutation in the same cell as the one that defines it, or try creating a new variable instead. Create new variables, don't mutate existing ones Mutate variables in the cells that define them Do this ...... not this `[](#__codelineno-4-1)df = pd.DataFrame({"my_column": [1, 2]}) [](#__codelineno-4-2)df["another_column"] = [3, 4]` `[](#__codelineno-5-1)df = pd.DataFrame({"my_column": [1, 2]})` `[](#__codelineno-6-1)df["another_column"] = [3, 4]` Global variable names must be unique[¶](#global-variable-names-must-be-unique "Permanent link") ----------------------------------------------------------------------------------------------- **marimo requires that every global variable be defined by only one cell.** This lets marimo keep code and outputs consistent. Global variables A variable can refer to any Python object. Functions, classes, and imported names are all variables. This rule encourages you to keep the number of global variables in your program small, which is generally considered good practice. ### Creating temporary variables[¶](#creating-temporary-variables "Permanent link") marimo provides two ways to define temporary variables, which can help keep the number of global variables in your notebook small. #### Creating local variables[¶](#creating-local-variables "Permanent link") Variables prefixed with an underscore (_e.g._, `_x`) are "local" to a cell: they can't be read by other cells. Multiple cells can reuse the same local variables names. #### Encapsulating code in functions[¶](#encapsulating-code-in-functions "Permanent link") If you want most or all the variables in a cell to be temporary, prefixing each variable with an underscore to make it local may feel inconvenient. In these situations we recommend encapsulating the temporary variables in a function. For example, if you find yourself copy-pasting the same plotting code across multiple cells and only tweaking a few parameters, try the following pattern: `[](#__codelineno-7-1)def _(): [](#__codelineno-7-2) import matplotlib.pyplot as plt [](#__codelineno-7-3) fig, ax = plt.subplots() [](#__codelineno-7-4) ax.plot([1, 2]) [](#__codelineno-7-5) return ax [](#__codelineno-7-6)[](#__codelineno-7-7)_()` Here, the variables `plt`, `fig`, and `ax` aren't added to the globals. ### Managing memory[¶](#managing-memory "Permanent link") Because variable names must be unique, you cannot reassign variables as a means of freeing memory. Instead, manage memory by encapsulating code in functions or using the `del` operator. See our guide on [expensive notebooks](https://docs.marimo.io/expensive_notebooks/#manage-memory) to learn more. Configuring how marimo runs cells[¶](#configuring-how-marimo-runs-cells "Permanent link") ----------------------------------------------------------------------------------------- Through the notebook settings menu, you can configure how and when marimo runs cells. In particular, you can disable autorun on startup, disable autorun on cell execution, and enable a module autoreloader. Read our [runtime configuration guide](https://docs.marimo.io/configuration/runtime_configuration/) to learn more. Disabling cells[¶](#disabling-cells "Permanent link") ----------------------------------------------------- Sometimes, you may want to edit one part of a notebook without triggering automatic execution of its dependent cells. For example, the dependent cells may take a long time to execute, and you only want to iterate on the first part of a multi-cell computation. For cases like this, marimo lets you **disable** cells: when a cell is disabled, it and its dependents are blocked from running. Disabling a cell blocks it from running. When you re-enable a cell, if any of the cell's ancestors ran while it was disabled, marimo will automatically run it. Enable a cell through the context menu. Stale cells run automatically. Interactive elements - marimo https://docs.marimo.io/guides/interactivity One of marimo's most powerful features is its first-class support for interactive user interface (UI) elements, or "widgets", created using [`marimo.ui`](https://docs.marimo.io/api/inputs/). **Interacting with a UI element bound to a global variable automatically runs all cells that reference it.** How interactions run cells[¶](#how-interactions-run-cells "Permanent link") --------------------------------------------------------------------------- Every UI element you make using [`marimo.ui`](https://docs.marimo.io/api/inputs/) has a value, accessible via its `value` attribute. When you interact with a UI element bound to a global variable, its value is sent back to Python. A single rule determines what happens next: Interaction rule When a UI element assigned to a global variable is interacted with, marimo automatically runs all cells that reference the variable (but don't define it). In the clip at the top of this page, interacting with the slider in the second cell re-runs the third cell (which outputs markdown) because it references the slider variable `x`. It doesn't re-run the second cell, because that cell defines `x`. **For interactions on a UI element to have any effect, the element must be assigned to a global variable.** Displaying UI elements[¶](#displaying-ui-elements "Permanent link") ------------------------------------------------------------------- Display UI elements in the output area above a cell by including them in the last expression, just like any other object. You can also embed elements in [markdown](https://docs.marimo.io/api/markdown/#marimo.md " marimo.md") using Python f-strings, like so: `[](#__codelineno-0-1)slider = mo.ui.slider(1, 10) [](#__codelineno-0-2)mo.md(f"Choose a value: {slider}")` Composite elements[¶](#composite-elements "Permanent link") ----------------------------------------------------------- Composite elements are advanced elements let you build UI elements out of other UI elements. The following composite elements are available: * [`mo.ui.array`](https://docs.marimo.io/api/inputs/array/#marimo.ui.array " marimo.ui.array") * [`mo.ui.dictionary`](https://docs.marimo.io/api/inputs/dictionary/#marimo.ui.dictionary " marimo.ui.dictionary") * [`mo.ui.batch`](https://docs.marimo.io/api/inputs/batch/#marimo.ui.batch " marimo.ui.batch") * [`mo.ui.form`](https://docs.marimo.io/api/inputs/form/#marimo.ui.form " marimo.ui.form") **Arrays and dictionaries.** Use [`mo.ui.array`](https://docs.marimo.io/api/inputs/array/#marimo.ui.array " marimo.ui.array") and [`mo.ui.dictionary`](https://docs.marimo.io/api/inputs/dictionary/#marimo.ui.dictionary " marimo.ui.dictionary") to logically group together related elements. These elements are especially useful when a set of UI elements is only known at runtime (so you can't assign each to a global variable individually, but can assign them to an array or dictionary). You can access the elements contained in an array or dictionary using Pythonic syntax, and embed these elements in other outputs. See their docstrings for code examples. **Batch and form.** Use these powerful elements to group together multiple UI elements into a single element with custom formatting, and gate the sending of an element's value on form submission. Use a form to gate value updates on submission Use an array to group together elements or create a collection of elements that is determined at runtime Building custom UI elements using our plugin API[¶](#building-custom-ui-elements-using-our-plugin-api "Permanent link") ----------------------------------------------------------------------------------------------------------------------- You can build your own reactive and interactive UI elements using [anywidget](https://github.com/manzt/anywidget). See [our docs on building custom UI elements](https://docs.marimo.io/integrating_with_marimo/custom_ui_plugins/) to learn more. FastAPI - marimo https://docs.marimo.io/guides/deploying/programmatically.html Running the marimo backend programmatically[¶](#running-the-marimo-backend-programmatically "Permanent link") ------------------------------------------------------------------------------------------------------------- marimo can be run programmatically using the `marimo` module. This is useful when you want to run marimo as part of a larger application or when you need to customize the behavior of marimo (e.g. middleware, custom error handling, authentication, routing, etc). FastAPI Example[¶](#fastapi-example "Permanent link") ----------------------------------------------------- Here's an example of how you can run a marimo application programmatically using FastAPI: `[](#__codelineno-0-1)from typing import Annotated, Callable, Coroutine [](#__codelineno-0-2)from fastapi.responses import HTMLResponse, RedirectResponse [](#__codelineno-0-3)import marimo [](#__codelineno-0-4)from fastapi import FastAPI, Form, Request, Response [](#__codelineno-0-5) [](#__codelineno-0-6)[](#__codelineno-0-7)# Create a marimo asgi app [](#__codelineno-0-8)server = ( [](#__codelineno-0-9) marimo.create_asgi_app() [](#__codelineno-0-10) .with_app(path="", root="./pages/index.py") [](#__codelineno-0-11) .with_app(path="/dashboard", root="./pages/dashboard.py") [](#__codelineno-0-12) .with_app(path="/sales", root="./pages/sales.py") [](#__codelineno-0-13)) [](#__codelineno-0-14)[](#__codelineno-0-15)# Create a FastAPI app [](#__codelineno-0-16)app = FastAPI() [](#__codelineno-0-17)[](#__codelineno-0-18)app.add_middleware(auth_middleware) [](#__codelineno-0-19)app.add_route("/login", my_login_route, methods=["POST"]) [](#__codelineno-0-20)[](#__codelineno-0-21)app.mount("/", server.build()) [](#__codelineno-0-22)[](#__codelineno-0-23)# Run the server [](#__codelineno-0-24)if __name__ == "__main__": [](#__codelineno-0-25) import uvicorn [](#__codelineno-0-26) [](#__codelineno-0-27) uvicorn.run(app, host="localhost", port=8000)` For a more complete example, see the [FastAPI example](https://github.com/marimo-team/marimo/tree/main/examples/frameworks/fastapi). Note that when run in this mode, marimo will serve its static assets under the name of the notebook (in the example above, that would be `http://hostname//assets/`). If you are using custom authorization middleware, skip authentication for these assets to avoid server round-trips. There are _many_ of them. Dynamic directory[¶](#dynamic-directory "Permanent link") --------------------------------------------------------- If you'd like to create a server to dynamically load marimo notebooks from a directory, you can use the `with_dynamic_directory` method. This is useful if the contents of the directory change often, such as a directory of notebooks for a dashboard, without restarting the server. `[](#__codelineno-1-1)server = ( [](#__codelineno-1-2) marimo.create_asgi_app() [](#__codelineno-1-3) .with_dynamic_directory(path="/dashboard", directory="./notebooks") [](#__codelineno-1-4))` If the notebooks in the directory are expected to be static, it is better to use the `with_app` method and loop through the directory contents. `[](#__codelineno-2-1)from pathlib import Path [](#__codelineno-2-2)server = marimo.create_asgi_app() [](#__codelineno-2-3)app_names: list[str] = [] [](#__codelineno-2-4)[](#__codelineno-2-5)notebooks_dir = Path(__file__).parent / "notebooks" [](#__codelineno-2-6)[](#__codelineno-2-7)for filename in sorted(notebooks_dir.iterdir()): [](#__codelineno-2-8) if filename.suffix == ".py": [](#__codelineno-2-9) app_name = filename.stem [](#__codelineno-2-10) server = server.with_app(path=f"/{app_name}", root=filename) [](#__codelineno-2-11) app_names.append(app_name)` Accessing Request Data[¶](#accessing-request-data "Permanent link") ------------------------------------------------------------------- Inside your marimo notebooks, you can access the current request data using `mo.app_meta().request`. This is particularly useful when implementing authentication or accessing user data. `[](#__codelineno-3-1)import marimo as mo [](#__codelineno-3-2)[](#__codelineno-3-3)# Access request data in your notebook [](#__codelineno-3-4)request = mo.app_meta().request [](#__codelineno-3-5)if request and request.user and request.user["is_authenticated"]: [](#__codelineno-3-6) content = f"Welcome {request.user['username']}!" [](#__codelineno-3-7)else: [](#__codelineno-3-8) content = "Please log in" [](#__codelineno-3-9)[](#__codelineno-3-10)mo.md(content)` ### Authentication Middleware Example[¶](#authentication-middleware-example "Permanent link") Here's an example of how to implement authentication middleware that populates `request.user`. Use a pure ASGI middleware Use a pure ASGI middleware (not Starlette's `BaseHTTPMiddleware`) so that `scope["user"]` and `scope["meta"]` are set for **both** HTTP and WebSocket connections. marimo uses WebSocket for real-time communication, and `BaseHTTPMiddleware` only runs for HTTP requests. `[](#__codelineno-4-1)class AuthMiddleware: [](#__codelineno-4-2) def __init__(self, app): [](#__codelineno-4-3) self.app = app [](#__codelineno-4-4) [](#__codelineno-4-5) async def __call__(self, scope, receive, send): [](#__codelineno-4-6) if scope["type"] in ("http", "websocket"): [](#__codelineno-4-7) # Add user data to the request scope [](#__codelineno-4-8) # This will be accessible via mo.app_meta().request.user [](#__codelineno-4-9) scope["user"] = { [](#__codelineno-4-10) "is_authenticated": True, [](#__codelineno-4-11) "username": "example_user", [](#__codelineno-4-12) # Add any other user data [](#__codelineno-4-13) } [](#__codelineno-4-14) # Optionally add metadata to the request [](#__codelineno-4-15) scope["meta"] = { [](#__codelineno-4-16) "some_key": "some_value", [](#__codelineno-4-17) } [](#__codelineno-4-18) await self.app(scope, receive, send) [](#__codelineno-4-19)[](#__codelineno-4-20)# Add the middleware to your FastAPI app [](#__codelineno-4-21)app.add_middleware(AuthMiddleware)` The `request` object provides access to: * `request.headers`: Request headers * `request.cookies`: Request cookies * `request.query_params`: Query parameters * `request.path_params`: Path parameters * `request.user`: User data added by authentication middleware * `request.url`: URL information including path, query parameters * `request.meta`: Metadata added by your custom middleware ### Documenting and Validating Query Parameters[¶](#documenting-and-validating-query-parameters "Permanent link") When mounted apps accept [query parameters](https://docs.marimo.io/api/query_params/), it can be helpful to declare, validate, and document them with the help of a [Pydantic model](https://fastapi.tiangolo.com/tutorial/query-param-models/). If a marimo app called `notebooks/items.py` is mounted to `/items`, declaring an endpoint with the same route will take the query parameters through Pydantic model validation first, then redirect to the marimo endpoint. `[](#__codelineno-5-1)# src/main.py [](#__codelineno-5-2)from fastapi import FastAPI, Request, Query [](#__codelineno-5-3)from fastapi.responses import RedirectResponse [](#__codelineno-5-4)from marimo import create_asgi_app [](#__codelineno-5-5)from pathlib import Path [](#__codelineno-5-6)from pydantic import BaseModel, Field [](#__codelineno-5-7)from typing import Annotated, Literal [](#__codelineno-5-8)from urllib.parse import urlencode [](#__codelineno-5-9) [](#__codelineno-5-10)[](#__codelineno-5-11)app = FastAPI() [](#__codelineno-5-12) [](#__codelineno-5-13)[](#__codelineno-5-14)class FilterParams(BaseModel): [](#__codelineno-5-15) limit: int = Field(100, gt=0, le=100) [](#__codelineno-5-16) offset: int = Field(0, ge=0) [](#__codelineno-5-17) order_by: Literal["created_at", "updated_at"] = "created_at" [](#__codelineno-5-18) tags: list[str] = [] [](#__codelineno-5-19) [](#__codelineno-5-20)[](#__codelineno-5-21)@app.get("/items") [](#__codelineno-5-22)async def marimo_items( [](#__codelineno-5-23) request: Request, filter_query: Annotated[FilterParams, Query()] [](#__codelineno-5-24)): [](#__codelineno-5-25) query_params = urlencode(filter_query.model_dump(), doseq=True) [](#__codelineno-5-26) return RedirectResponse(url=f"/items/?{query_params}") [](#__codelineno-5-27) [](#__codelineno-5-28)[](#__codelineno-5-29)server = create_asgi_app(include_code=True, quiet=False) [](#__codelineno-5-30)notebooks_dir = Path(__file__).parent.parent / "notebooks" [](#__codelineno-5-31)[](#__codelineno-5-32)for filename in notebooks_dir.iterdir(): [](#__codelineno-5-33) if filename.suffix == ".py": [](#__codelineno-5-34) app_name = filename.stem [](#__codelineno-5-35) server = server.with_app(path=f"/{app_name}", root=filename) [](#__codelineno-5-36) [](#__codelineno-5-37)[](#__codelineno-5-38)app.mount("/", server.build())` Under the Hood[¶](#under-the-hood "Permanent link") --------------------------------------------------- Behind the scenes, in this mode, marimo is spinning up a new computational kernel in a separate sub-thread (same process) for each new session / app created. There are a few implications of this from a performance and reliability perspective: * If you are running multiple instances of this same server for load balancing, you will need to use sticky sessions in your load balancer to ensure that the same client gets the same kernel each time. * Similarly, attempting to run multiple instances of the same FastAPI process (a common approach with Python web services) on the same node will not work reliably, since only one of them will actually be running the kernel. In summary, there are limitations to how far the approach described here can horizontally scale, so we recommend scaling vertically first. In other words, increase the container CPU/Memory specs before increasing the number of container instances.