Star 22,002
Python
Dash Python > Advanced Callbacks
Advanced Callbacks
To get the most out of this page, make sure you've read about Basic Callbacks in
the Dash Fundamentals.
Catching Errors with PreventUpdate
In certain situations, you don't want to update the callback output. You can
achieve this by raising a PreventUpdate exception in the callback function.
from dash import Dash, html, Input, Output, callback
from dash.exceptions import PreventUpdate
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP
app = Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div([
html.Button('Click here to see the content', id='show-secre
html.Div(id='body-div')
])
@callback(
Output('body-div', 'children'),
Input('show-secret', 'n_clicks')
)
def update_output(n_clicks):
if n_clicks is None:
raise PreventUpdate
else:
return "Elephants are the only animal that can't jump"
if __name__ == '__main__':
app.run(debug=True)
CLICK HERE TO SEE THE CONTENT
Displaying Errors with dash.no_update
This example illustrates how you can show an error while keeping the
previous input, using dash.no_update to update only some of the callback
outputs.
from dash import Dash, dcc, html, Input, Output, callback, no_
from dash.exceptions import PreventUpdate
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwg
app = Dash(__name__, external_stylesheets=external_stylesheets
app.layout = html.Div([
html.P('Enter a composite number to see its prime factors'
dcc.Input(id='num', type='number', debounce=True, min=2, s
html.P(id='err', style={'color': 'red'}),
html.P(id='out')
])
@callback(
Output('out', 'children'),
Output('err', 'children'),
Input('num', 'value')
)
def show_factors(num):
if num is None:
# PreventUpdate prevents ALL outputs updating
raise PreventUpdate
factors = prime_factors(num)
if len(factors) == 1:
# dash.no_update prevents any single output updating
# (note: it's OK to use for a single-output callback t
return no_update, '{} is prime!'.format(num)
return '{} is {}'.format(num, ' * '.join(str(n) for n in f
def prime_factors(num):
n, i, out = num, 2, []
Enter a composite number to see its prime factors
Updating Component Properties when a Callback
is Running
New in Dash 2.16
You can use the running argument on a callback to update specific
component-property pairs when the callback is running. For example, you
could disable the button that triggered the callback while the callback is still
running.
running accepts a list of three element tuples, where:
The first element of each tuple must be an Output dependency object
referencing a property of a component in the app layout.
The second element is the value that the property should be set to
while the callback is running.
The third element is the value the property should be set to when the
callback completes.
In the following example, our running argument sets the disabled
property on the submit-button to True while the callback is running and
sets it back to False once the callback completes.
from dash import Dash, dcc, html, Input, Output, State, callbac
import time
app = Dash()
app.layout = html.Div([
html.Div(dcc.Input(id='input-on-submit-text', type='text'))
html.Button('Submit', id='submit-button', n_clicks=0),
html.Div(id='container-output-text',
children='Enter a value and press submit')
])
@callback(
Output('container-output-text', 'children'),
Input('submit-button', 'n_clicks'),
State('input-on-submit-text', 'value'),
prevent_initial_call=True,
running=[(Output("submit-button", "disabled"), True, False)
)
def update_output(n_clicks, value):
time.sleep(5)
return 'The input value was "{}" and the button has been cl
value,
n_clicks
)
if __name__ == '__main__':
app.run(debug=True)
SUBMIT
Enter a value and press submit
There is a known issue where using running with a multi-pages app doesn't work
as expected when a user changes page when the callback is running.
Determining which Input Has Fired with
dash.callback_context
In addition to event properties like n_clicks that change whenever an
event happens (in this case a click), there is a global variable
dash.callback_context , available only inside a callback. Using
dash.callback_context , you can determine which component/property
pairs triggered a callback.
Below is a summary of properties of dash.callback_context outlining
the basics of when to use them. For more detail and examples see
Determining Which Callback Input Changed.
For more examples of minimal Dash apps that use
dash.callback_context , go to the community-driven Example Index.
Properties for callback_context
In Dash 2.4 and later, dash.callback_context (or dash.ctx ) has three
additional properties to make it easier to work with.
triggered_id : The id of the component that triggered the callback.
triggered_prop_ids : A dictionary of the component ids and props
that triggered the callback. Useful when multiple inputs can trigger the
callback at the same time, or multiple properties of the same
component can trigger the callback.
args_grouping : A dictionary of the inputs used with flexible callback
signatures. The keys are the variable names and the values are
dictionaries containing:
"id": the component ID. If it’s a pattern matching ID, it will be a
dict.
"id_str": for pattern matching IDs, it’s the stringified dict ID
with no white spaces.
"property": the component property used in the callback.
"value": the value of the component property at the time the
callback was fired.
"triggered": a boolean indicating whether this input triggered
the callback.
Dash 2.4 and earlier versions of Dash have the following properties
triggered : list of all the Input props that changed and caused the
callback to execute. It is empty when the callback is called on initial load,
unless an Input prop got its value from another initial callback.
Callbacks triggered by user actions typically have one item in
triggered , unless the same action changes two props at once or the
callback has several Input props that are all modified by another
callback based on a single user action.
More about empty triggered lists: For backward compatibility purposes,
an empty triggered is not really empty. It's falsy so that you can use if
triggered to detect the initial call, but it still has a placeholder element so
that ctx.triggered[0]["prop_id"].split(".") yields a blank ID and
prop ["", ""] instead of an error.
inputs and states : allow you to access the callback params by ID
and prop instead of through the function args. These have the form of
dictionaries { 'component_id.prop_name': value }
outputs_list , inputs_list , and states_list : lists of inputs,
outputs, and state items arranged as you'll find them in the callback
arguments and return value. This is mostly useful for pattern-matching
callbacks.
response : The HTTP response object being constructed, useful for
changing cookies.
record_timing : a method to report granular timing information, to
be seen in the Dev Tools.
Here's an example of how this can be done:
import json
from dash import Dash, html, Input, Output, callback, ctx
app = Dash()
app.layout = html.Div([
html.Button('Button 1', id='btn-1'),
html.Button('Button 2', id='btn-2'),
html.Button('Button 3', id='btn-3'),
html.Div(id='container')
])
@callback(Output('container', 'children'),
Input('btn-1', 'n_clicks'),
Input('btn-2', 'n_clicks'),
Input('btn-3', 'n_clicks'))
def display(btn1, btn2, btn3):
if not ctx.triggered_id:
button_id = 'No clicks yet'
else:
button_id = ctx.triggered_id
ctx_msg = json.dumps({
'states': ctx.states,
'triggered': ctx.triggered,
'inputs': ctx.inputs
}, indent=2)
return html.Div([
html.Table([
html.Tr([html.Th('Button 1'),
html.Th('Button 2'),
html.Th('Button 3'),
BUTTON 1 BUTTON 2 BUTTON 3
Button 1 Button 2 Button 3 Most Recent Click
0 0 0 No clicks yet
{
"states": {},
"triggered": [],
"inputs": {
"btn-1.n_clicks": null,
"btn-2.n_clicks": null,
"btn-3.n_clicks": null
}
}
Improving Performance with Memoization
Memoization allows you to bypass long computations by storing the results
of function calls.
To better understand how memoization works, let's start with a simple
example.
import time
import functools32
@functools32.lru_cache(maxsize=32)
def slow_function(input):
time.sleep(10)
return f'Input was {input}'
Calling slow_function('test') the first time will take 10 seconds. Calling
it a second time with the same argument will take almost no time since the
previously computed result was saved in memory and reused.
The Performance section of the Dash docs delves a little deeper into
leveraging multiple processes and threads in conjunction with memoization
to further improve performance.
Sign up for Dash Club → Two free cheat sheets plus updates from Chris
Parmer and Adam Schroeder delivered to your inbox every two months.
Includes tips and tricks, community apps, and deep dives into the Dash
architecture. Join now.
When Are Callbacks Executed?
This section describes the circumstances under which the dash-renderer
front-end client can make a request to the Dash back-end server (or the
clientside callback code) to execute a callback function.
When a Dash App First Loads
All of the callbacks in a Dash app are executed with the initial value of their
inputs when the app is first loaded. This is known as the "initial call" of the
callback. To learn how to suppress this behavior, see the documentation for
the prevent_initial_call attribute of Dash callbacks.
It is important to note that when a Dash app is initially loaded in a web
browser by the dash-renderer front-end client, its entire callback chain is
introspected recursively.
This allows the dash-renderer to predict the order in which callbacks will
need to be executed, as callbacks are blocked when their inputs are outputs
of other callbacks which have not yet fired. In order to unblock the execution
of these callbacks, first callbacks whose inputs are immediately available
must be executed. This process helps the dash-renderer to minimize the
time and effort it uses, and avoid unnecessarily redrawing the page, by
making sure it only requests that a callback is executed when all of the
callback's inputs have reached their final values.
Examine the following Dash app:
from dash import Dash, html, Input, Output, callback
app = Dash()
app.layout = html.Div(
[
html.Button("execute callback", id="button_1"),
html.Div(children="callback not executed", id="first_ou
html.Div(children="callback not executed", id="second_o
]
)
@callback(
Output("first_output_1", "children"),
Output("second_output_1", "children"),
Input("button_1", "n_clicks")
)
def change_text(n_clicks):
return ["n_clicks is " + str(n_clicks), "n_clicks is " + st
if __name__ == '__main__':
app.run(debug=True)
EXECUTE CALLBACK
n_clicks is None
n_clicks is None
Notice that when this app is finished being loaded by a web browser and
ready for user interaction, the html.Div components do not say "callback
not executed" as declared in the app's layout, but rather "n_clicks is None" as
the result of the change_text() callback being executed. This is because
the "initial call" of the callback occurred with n_clicks having the value of
None .
As a Direct Result of User Interaction
Most frequently, callbacks are executed as a direct result of user interaction,
such as clicking a button or selecting an item in a dropdown menu. When
such interactions occur, Dash components communicate their new values to
the dash-renderer front-end client, which then requests that the Dash
server execute any callback function that has the newly changed value as
input.
If a Dash app has multiple callbacks, the dash-renderer requests callbacks
to be executed based on whether or not they can be immediately executed
with the newly changed inputs. If several inputs change simultaneously, then
requests are made to execute them all.
Whether or not these requests are executed in a synchronous or
asynchronous manner depends on the specific setup of the Dash back-end
server. If it is running in a multi-threaded environment, then all of the
callbacks can be executed simultaneously, and they will return values based
on their speed of execution. In a single-threaded environment however,
callbacks will be executed one at a time in the order they are received by the
server.
In the example application above, clicking the button results in the callback
being executed.
As an Indirect Result of User Interaction
When a user interacts with a component, the resulting callback might have
outputs that are themselves the input of other callbacks. The dash-
renderer will block the execution of such a callback until the callback whose
output is its input has been executed.
Take the following Dash app:
from dash import Dash, html, Input, Output, callback
from datetime import datetime
import time
app = Dash()
app.layout = html.Div(
[
html.Button("execute fast callback", id="button_3"),
html.Button("execute slow callback", id="button_4"),
html.Div(children="callback not executed", id="first_o
html.Div(children="callback not executed", id="second_
html.Div(children="callback not executed", id="third_o
]
)
@callback(
Output("first_output_3", "children"),
Input("button_3", "n_clicks"))
def first_callback(n):
now = datetime.now()
current_time = now.strftime("%H:%M:%S")
return "in the fast callback it is " + current_time
@callback(
Output("second_output_3", "children"), Input("button_4", "
def second_callback(n):
time.sleep(5)
now = datetime.now()
current_time = now.strftime("%H:%M:%S")
return "in the slow callback it is " + current_time
E X E C U T E FA S T C A L L B A C K EXECUTE SLOW CALLBACK
in the fast callback it is 10:48:49
in the slow callback it is 10:48:54
in the third callback it is 10:48:55
The above Dash app demonstrates how callbacks chain together. Notice that
if you first click "execute slow callback" and then click "execute fast callback",
the third callback is not executed until after the slow callback finishes
executing. This is because the third callback has the second callback's output
as its input, which lets the dash-renderer know that it should delay its
execution until after the second callback finishes.
When Dash Components Are Added to the Layout
It is possible for a callback to insert new Dash components into a Dash app's
layout. If these new components are themselves the inputs to other callback
functions, then their appearance in the Dash app's layout will trigger those
callback functions to be executed.
In this circumstance, it is possible that multiple requests are made to execute
the same callback function. This would occur if the callback in question has
already been requested and its output returned before the new components
which are also its inputs are added to the layout.
Prevent Callback Execution Upon Initial
Component Render
You can use the prevent_initial_call attribute to prevent callbacks
from firing when their inputs initially appear in the layout of your Dash
application.
This attribute applies when the layout of your Dash app is initially loaded, and
also when new components are introduced into the layout when a callback
has been triggered.
from dash import Dash, html, Input, Output, callback
from datetime import datetime
import time
app = Dash()
app.layout = html.Div(
[
html.Button("execute callbacks", id="button_2"),
html.Div(children="callback not executed", id="first_o
html.Div(children="callback not executed", id="second_
html.Div(children="callback not executed", id="third_o
html.Div(children="callback not executed", id="fourth_
]
)
@callback(
Output("first_output_2", "children"),
Output("second_output_2", "children"),
Input("button_2", "n_clicks"), prevent_initial_call=True)
def first_callback(n):
now = datetime.now()
current_time = now.strftime("%H:%M:%S")
return ["in the first callback it is " + current_time, "in
@callback(
Output("third_output_2", "children"), Input("second_output
def second_callback(n):
time.sleep(2)
now = datetime.now()
current_time = now.strftime("%H:%M:%S")
EXECUTE CALLBACKS
callback not executed
callback not executed
callback not executed
callback not executed
However, the above behavior only applies if both the callback output and
input are present in the app layout upon initial load of the application.
It is important to note that prevent_initial_call will not prevent a
callback from firing in the case where the callback's input is inserted into the
layout as the result of another callback after the app initially loads unless the
output is inserted alongside that input!
In other words, if the output of the callback is already present in the app
layout before its input is inserted into the layout, prevent_initial_call
will not prevent its execution when the input is first inserted into the layout.
Consider the following example:
from dash import Dash, dcc, html, Input, Output, callback
app = Dash(__name__, suppress_callback_exceptions=True)
server = app.server
app.layout = html.Div([
dcc.Location(id='url'),
html.Div(id='layout-div'),
html.Div(id='content')
])
@callback(Output('content', 'children'), Input('url', 'pathname
def display_page(pathname):
return html.Div([
dcc.Input(id='input', value='hello world'),
html.Div(id='output')
])
@callback(Output('output', 'children'), Input('input', 'value')
def update_output(value):
print('>>> update_output')
return value
@callback(Output('layout-div', 'children'), Input('input', 'val
def update_layout_div(value):
print('>>> update_layout_div')
return value
In this case, prevent_initial_call will prevent the update_output()
callback from firing when its input is first inserted into the app layout as a
result of the display_page() callback. This is because both the input and
output of the callback are already contained within the app layout when the
callback executes.
However, because the app layout contains only the output of the callback,
and not its input, prevent_initial_call will not prevent the
update_layout_div() callback from firing. Since
suppress_callback_exceptions=True is specified here, Dash has to
assume that the input is present in the app layout when the app is initialized.
From the perspective of the output element in this example, the new input
component is handled as if an existing input had been provided a new value,
rather than treating it as initially rendered.
Callbacks with No Outputs
New in 2.17
All previous examples have inputs that trigger callbacks as well as outputs
that are updated. Callbacks also support having no outputs. This can be
useful for cases where you want some code to run when an action triggers a
callback, but you don't want to update any component property. For
example, you may want to fetch some data and save it, send emails, or
interact with other external services outside of the Dash ecosystem.
In the following example, using the dcc.Upload component, we allow the
user to upload a file to the server.
Our example has no return statements. Callbacks without outputs should
not return a value, because there are no outputs to update. If you return a
value from the callback when there is no output to update, you'll see an error
in Dash Dev Tools.
import base64
from dash import Dash, html, Input, Output, dcc, callback, Sta
app = Dash(__name__)
app.layout = html.Div(
[
html.H1("No Output Example"),
dcc.Upload(
id='upload-data-to-server',
children=html.Div([
'Drag and Drop or ',
html.A('Select Files')
]),
style={
'width': '100%',
'height': '60px',
'lineHeight': '60px',
'borderWidth': '1px',
'borderStyle': 'dashed',
'borderRadius': '5px',
'textAlign': 'center',
'margin': '10px'
},
),
]
)
@callback(
Input("upload-data-to-server", "contents"),
State('upload-data-to-server', 'filename'),
Setting Properties Directly
New in 2.17
You can update component-property pairs directly from a callback without
them being callback outputs by using set_props . With this approach,
conditionally updating different component-property pairs is simpler because
you don't need to add them all as outputs and use dash.no_update .
set_props takes the ID of the component to update as its first argument,
followed by a dict of properties to update. Each dict key should be a
property name, with the key's value being the value to update the
component property to.
Here, we have a callback that uses set_props to set the modal's is_open
property to False when the callback is triggered by a user selecting the
modal_close button. Otherwise, it's set to True and the modal content is
displayed. We have no outputs on this callback, but set_props can also be
combined with outputs.
This example is based on the Popup On Row Selection Example on the Dash
AG Grid page, which instead uses outputs and dash.no_update .
On callbacks that don't run in the background, like in the following example,
updates made using set_props and via outputs all happen at the same time,
when the callback finishes running. On background callbacks, set_props
updates take place immediately. See the Background Callbacks page for an
example.
import dash_ag_grid as dag
from dash import Dash, Input, html, ctx, callback, set_props
import dash_bootstrap_components as dbc
app = Dash(__name__, external_stylesheets=[dbc.themes.SPACELAB
rowData = [
{"make": "Toyota", "model": "Celica", "price": 35000},
{"make": "Ford", "model": "Mondeo", "price": 32000},
{"make": "Porsche", "model": "Boxster", "price": 72000},
]
app.layout = html.Div(
[
dag.AgGrid(
id="setprops-row-selection-popup",
rowData=rowData,
columnDefs=[{"field": i} for i in ["make", "model"
columnSize="sizeToFit",
dashGridOptions={"rowSelection": "single", "animat
),
dbc.Modal(
[
dbc.ModalHeader("More information about select
dbc.ModalBody(id="setprops-row-selection-modal
dbc.ModalFooter(dbc.Button("Close", id="setpro
],
id="setprops-row-selection-modal",
),
]
)
@callback(
Input("setprops-row-selection-popup", "selectedRows"),
Make Model Price
Toyota Celica 35000
Ford Mond… 32000
Porsc… Boxst… 72000
In the example above, we use set_props to simplify the code. In other
cases, however, using Outputs may lead to simpler code because the
Outputs are defined in the callback signature, making it easier to tell which
component properties a callback updates.
Limitations
Component properties updated using set_props won't appear in the
callback graph for debugging.
Component properties updated using set_props won't appear as
loading when they are wrapped with a `dcc.Loading` component.
set_props doesn't validate the id or property names provided, so
no error will be displayed if they contain typos. This can make apps that
use set_props harder to debug.
Using set_props with chained callbacks may lead to unexpected
results.
Circular Callbacks
As of dash v1.19.0 , you can create circular updates within the same
callback.
Circular callback chains that involve multiple callbacks are not supported.
Circular callbacks can be used to keep multiple inputs synchronized to each
other.
Synchronizing a Slider with a Text Input Example
from dash import Dash, html, dcc, Input, Output, callback, ctx
external_stylesheets = ["https://codepen.io/chriddyp/pen/bWLwgP
app = Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div(
[
dcc.Slider(
id="slider-circular", min=0, max=20,
marks={i: str(i) for i in range(21)},
value=3
),
dcc.Input(
id="input-circular", type="number", min=0, max=20,
),
]
)
@callback(
Output("input-circular", "value"),
Output("slider-circular", "value"),
Input("input-circular", "value"),
Input("slider-circular", "value"),
)
def callback(input_value, slider_value):
trigger_id = ctx.triggered[0]["prop_id"].split(".")[0]
value = input_value if trigger_id == "input-circular" else
return value, value
if __name__ == '__main__':
app.run(debug=True)
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Displaying Two Inputs with Different Units Example
from dash import Dash, html, dcc, Input, Output, callback, ctx
external_stylesheets = ["https://codepen.io/chriddyp/pen/bWLwg
app = Dash(__name__, external_stylesheets=external_stylesheets
app.layout = html.Div([
html.Div('Convert Temperature'),
'Celsius',
dcc.Input(
id="celsius",
value=0.0,
type="number"
),
' = Fahrenheit',
dcc.Input(
id="fahrenheit",
value=32.0,
type="number",
),
])
@callback(
Output("celsius", "value"),
Output("fahrenheit", "value"),
Input("celsius", "value"),
Input("fahrenheit", "value"),
)
def sync_input(celsius, fahrenheit):
input_id = ctx.triggered[0]["prop_id"].split(".")[0]
if input_id == "celsius":
fahrenheit= None if celsius is None else (float(celsiu
else:
celsius = None if fahrenheit is None else (float(fahre
Convert Temperature
Celsius 0 = Fahrenheit
32
Synchronizing Two Checklists
from dash import Dash, dcc, html, Input, Output, callback, call
external_stylesheets = ["https://codepen.io/chriddyp/pen/bWLwgP
app = Dash(__name__, external_stylesheets=external_stylesheets)
options = ["New York City", "Montréal", "San Francisco"]
app.layout = html.Div(
[
dcc.Checklist(["All"], [], id="all-checklist", inline=T
dcc.Checklist(options, [], id="city-checklist", inline=
]
)
@callback(
Output("city-checklist", "value"),
Output("all-checklist", "value"),
Input("city-checklist", "value"),
Input("all-checklist", "value"),
)
def sync_checklists(cities_selected, all_selected):
ctx = callback_context
input_id = ctx.triggered[0]["prop_id"].split(".")[0]
if input_id == "city-checklist":
all_selected = ["All"] if set(cities_selected) == set(o
else:
cities_selected = options if all_selected else []
return cities_selected, all_selected
if __name__ == "__main__":
app.run(debug=True)
All
New York City Montréal San Francisco
Dash Python > Advanced Callbacks
Products Pricing About Us Support Join our
Dash Enterprise Careers Community mailing list
Pricing Support
Consulting and Resources
Training Graphing Sign up to stay in
Blog Documentation
the loop with all
things Plotly —
from Dash Club
to product
updates,
webinars, and
more!
SUBSCRIBE
Copyright © 2025 Plotly. All rights reserved. Terms of Service Privacy Policy