The minimum viable DashExcalidraw — one component, default props, a working canvas.

Basic usage

The minimum viable DashExcalidraw — one component, default props, a working canvas.


Overview

The smallest useful app is one component with default props. Draw on the canvas below — zoom, pan, undo, the shape tools, the library and the context menu all work with no configuration at all.

That is the point of this page: nothing on it is set up. Everything you can do to the canvas is Excalidraw's own behaviour, reaching Dash unmodified.

What you get for free

Mounting DashExcalidraw with nothing but an id gives you the full editor:

text, image, eraser and the frame tool, with keyboard shortcuts (1–9).

(Cmd/Ctrl + arrow key), scene search, image cropping, element linking and the command palette.

None of that costs you a callback.

The minimum app

from dash import Dash
from dash_excalidraw import DashExcalidraw

app = Dash(__name__)
app.layout = DashExcalidraw(id="canvas", height="600px")

if __name__ == "__main__":
    app.run(debug=True)

height is the prop you will actually change. Excalidraw fills its parent, so a canvas that looks too short is almost always a container-height problem rather than a component one.

Live demo

Reading what the user drew

The component writes its state back through ordinary props, so a callback reads the canvas the same way it reads a dropdown:

from dash import Input, Output, callback

@callback(Output("count", "children"), Input("canvas", "elements"))
def show(elements):
    return f"{len(elements or [])} elements"

elements updates on every scene change. If you only need to know that something changed — not what — read sceneVersion instead; it is a single integer and far cheaper to compare than diffing the element array.

Four switches you may need in a real app

The defaults suit a canvas that owns its page. An app with other inputs, or a canvas embedded in a longer scrolling document, usually wants one or two of these changed.

PropDefaultTurn it off when
handleKeyboardGloballyTrueYour page has other inputs. Shortcuts otherwise fire while the user types elsewhere.
autoFocusTrueThe canvas is below the fold, or another field should hold focus on load.
detectScrollTrueThe canvas sits inside a scrolling container and swallowing wheel events feels like a trap.
langCode"en"You want another UI language — "fr-FR", "zh-CN", and so on.
DashExcalidraw(
    id="canvas",
    handleKeyboardGlobally=False,  # a form on the same page owns the keyboard
    autoFocus=False,
    detectScroll=False,            # the page scrolls; the canvas should not eat it
    langCode="fr-FR",
)

handleKeyboardGlobally is the one worth thinking about first. It moves Excalidraw's key handling from the canvas to the document, which is what makes single-key shortcuts work without clicking the canvas — and also what puts it in the same room as every other keyboard consumer on your page. If you have your own shortcuts, a modal, or a form that shares the layout, turn it off and let the canvas take focus before it takes keys.

Where to go next

Source

# File: docs/basic-usage/basic.py

"""Basic usage: the minimum viable DashExcalidraw."""

import dash_mantine_components as dmc

from dash_excalidraw import DashExcalidraw
from docs._shared import canvas_frame, code_block, sync_canvas_theme

sync_canvas_theme("basic-canvas")

CODE = """
from dash import Dash
from dash_excalidraw import DashExcalidraw

app = Dash(__name__)
app.layout = DashExcalidraw(id='canvas', height='600px')
"""


component = dmc.Stack(
    gap="md",
    children=[
        code_block(CODE),
        canvas_frame(DashExcalidraw(id="basic-canvas", height="600px")),
    ],
)

:defaultExpanded: false :withExpandedButton: true

Component reference

Every prop on the component, generated from the TypeScript source.


Source: /basic

Note for AI agents: This is the static, prerendered view of an interactive Dash application served because we detected a non-JS user agent. Full prose docs: