name: app-callback-workflows
description: "Use for Plotly Dash app layouts, callbacks, pages, assets,
configuration, clientside callbacks, Jupyter display, CSP, and app-level
debugging."
disable-model-invocation: true
metadata:
disco-role: operating
license: MIT
Dash App and Callback Workflows
Use this sub-skill when a task is about using Dash as an application framework:
creating layouts, registering callbacks, debugging ID/dependency validation,
configuring pages/assets, or moving work into clientside callbacks.
Start here
- For layout and callback API details, read
references/callbacks-and-layouts.md.
- For pages, URL prefixes, assets, dev tools, Jupyter, and CSP, read
references/pages-assets-and-config.md.
- For browser-side callback functions, read
references/clientside-callbacks.md.
- For common failures, read
references/troubleshooting.md.
- Run scripts/smoke_dash_app.py for a no-browser
import/layout/callback smoke check and
scripts/smoke_pages_app.py for a page-registry
smoke check.
Main routes
Build a basic app
Use Dash, component modules, and a component tree:
from dash import Dash, html, dcc
app = Dash(__name__)
app.layout = html.Div([
dcc.Input(id="input", value="initial"),
html.Div(id="output"),
])
Important rules:
- Layout children must be Dash components, strings, numbers,
None, or lists of
those values. Raw arbitrary dicts are not valid component children.
- Component IDs can be strings or dictionaries. Use dictionary IDs for
pattern-matching callbacks.
- If a layout is generated dynamically, either ensure callback components exist
in the initial validation layout or configure dynamic-layout behavior
deliberately.
Register server-side callbacks
Use @app.callback when you have an app object and @dash.callback when you
need module-level callback registration. Core dependency classes are Output,
Input, and State.
from dash import Input, Output, State, callback, no_update
from dash.exceptions import PreventUpdate
@callback(Output("output", "children"), Input("input", "value"), State("store", "data"))
def update(value, stored):
if value is None:
raise PreventUpdate
if value == "keep":
return no_update
return f"{value}: {stored}"
Use callback troubleshooting when callbacks do
not fire, fire too early, reference missing components, or form circular
dependencies.
Use pattern-matching IDs
Route to dictionary IDs and wildcards when components are generated from data:
from dash import MATCH, ALL, Input, Output
@app.callback(
Output({"type": "row-output", "index": MATCH}, "children"),
Input({"type": "row-input", "index": MATCH}, "value"),
)
def per_row(value):
return value
Use MATCH for one-to-one dynamic pairs, ALL for all matching components, and
ALLSMALLER when a callback needs earlier indexed values.
Inspect callback context
Use dash.ctx or dash.callback_context inside callbacks for trigger metadata:
ctx.triggered_id gives the component ID that triggered the callback.
ctx.triggered_prop_ids maps changed id.property strings to IDs.
ctx.args_grouping is useful with flexible callback signatures.
ctx.response lets a callback set response cookies/headers in supported
backends.
ctx.websocket is only available for WebSocket callbacks; route those tasks
to server backends and async.
Use pages, assets, and URL prefixes
Use Dash(__name__, use_pages=True) plus dash.register_page and
dash.page_container for multi-page apps. Read
pages-assets-and-config.md before
changing URL prefixes, asset loading, or Jupyter display behavior.
Move simple work clientside
Use clientside callbacks for simple browser-side transformations, browser
storage access, or UI work that should avoid a server round trip. Read
clientside-callbacks.md for namespace
registration, no_update, PreventUpdate, and set_props behavior.
Route elsewhere
Validation checklist
Before declaring an app/callback fix complete:
- The app imports
Dash, html, dcc, and dependency classes from dash.
- Every callback component ID exists in the layout, validation layout, or a
deliberate dynamic-layout configuration.
- Callback return shape matches the Output grouping.
- Browser console is clean for browser-backed tasks.
- If assets, pages, or URL prefixes changed, the generated URLs use
app.get_asset_url, dash.get_relative_path, or the app's configured
prefix-aware helpers.