Events are the mechanism that makes Gradio applications interactive. An event listener connects a component interaction (like a button click) to a Python function, allowing you to respond to user actions in real-time.
What are events?
In Gradio, events are triggered by user interactions with components. When an event occurs, Gradio can:
- Run a Python function
- Pass component values as inputs to that function
- Update other components with the function’s outputs
This creates the interactive loop that powers Gradio applications.
Basic event structure
Every event listener follows this pattern:
component.event_name(
fn=function_to_run,
inputs=[input_components],
outputs=[output_components]
)
For example:
import gradio as gr
def greet(name):
return f"Hello, {name}!"
with gr.Blocks() as demo:
name_input = gr.Textbox(label="Name")
output = gr.Textbox(label="Greeting")
button = gr.Button("Greet")
button.click(fn=greet, inputs=name_input, outputs=output)
Common event types
Click events
Triggered when a button is clicked:
import gradio as gr
def process():
return "Button clicked!"
with gr.Blocks() as demo:
output = gr.Textbox()
button = gr.Button("Click me")
button.click(fn=process, inputs=None, outputs=output)
Change events
Triggered when a component’s value changes:
import gradio as gr
def update(text):
return text.upper()
with gr.Blocks() as demo:
inp = gr.Textbox(label="Type here")
out = gr.Textbox(label="Uppercase")
inp.change(fn=update, inputs=inp, outputs=out)
The .change() event fires both when users type AND when the value is updated programmatically. Use .input() for events triggered only by user input.
Submit events
Triggered when users press Enter in a textbox:
import gradio as gr
def process(text):
return f"You submitted: {text}"
with gr.Blocks() as demo:
inp = gr.Textbox(label="Press Enter to submit")
out = gr.Textbox()
inp.submit(fn=process, inputs=inp, outputs=out)
Triggered only by direct user input (not programmatic updates):
import gradio as gr
def count_chars(text):
return f"Character count: {len(text)}"
with gr.Blocks() as demo:
inp = gr.Textbox(label="Type here")
out = gr.Textbox(label="Count")
inp.input(fn=count_chars, inputs=inp, outputs=out)
Select events
Triggered when selecting items in components like Gallery, Dataframe, or highlighted text:
import gradio as gr
def show_selection(evt: gr.SelectData):
return f"You selected: {evt.value} at index {evt.index}"
with gr.Blocks() as demo:
gallery = gr.Gallery([("cat.jpg", "Cat"), ("dog.jpg", "Dog")])
output = gr.Textbox()
gallery.select(fn=show_selection, inputs=None, outputs=output)
Event data objects
Some events provide additional context through event data classes:
SelectData
Contains information about selected items:
import gradio as gr
def on_select(evt: gr.SelectData):
return f"Index: {evt.index}, Value: {evt.value}"
with gr.Blocks() as demo:
dataframe = gr.Dataframe([[1, 2], [3, 4]])
output = gr.Textbox()
dataframe.select(fn=on_select, inputs=None, outputs=output)
SelectData attributes:
evt.index - Index of selected item (or tuple for 2D components)
evt.value - Value of selected item
evt.selected - True if selected, False if deselected
evt.target - The component that triggered the event
LikeData
For chatbot like/dislike events:
import gradio as gr
def handle_like(evt: gr.LikeData):
action = "liked" if evt.liked else "disliked"
return f"You {action} message {evt.index}: {evt.value}"
with gr.Blocks() as demo:
chatbot = gr.Chatbot([["Hello", "Hi there!"]])
output = gr.Textbox()
chatbot.like(fn=handle_like, inputs=None, outputs=output)
LikeData attributes:
evt.index - Index of the liked/disliked message
evt.value - Content of the message
evt.liked - True if liked, False if disliked
KeyUpData
For key press events:
import gradio as gr
def on_key(evt: gr.KeyUpData):
return f"Key: {evt.key}, Input: {evt.input_value}"
with gr.Blocks() as demo:
dropdown = gr.Dropdown(["a", "b", "c"], allow_custom_value=True)
output = gr.JSON()
dropdown.key_up(fn=on_key, inputs=None, outputs=output)
Event chaining
Chain events together using .then(), .success(), and .failure():
Sequential execution with .then()
import gradio as gr
def step1(text):
return text.upper()
def step2(text):
return text + "!!!"
with gr.Blocks() as demo:
inp = gr.Textbox()
mid = gr.Textbox()
out = gr.Textbox()
btn = gr.Button("Process")
btn.click(fn=step1, inputs=inp, outputs=mid).then(
fn=step2, inputs=mid, outputs=out
)
Success and failure handlers
import gradio as gr
def risky_operation(x):
if x < 0:
raise ValueError("Negative numbers not allowed!")
return x * 2
def on_success():
return "Operation completed successfully!"
def on_failure():
return "Operation failed!"
with gr.Blocks() as demo:
inp = gr.Number()
out = gr.Number()
status = gr.Textbox()
btn = gr.Button("Calculate")
btn.click(
fn=risky_operation, inputs=inp, outputs=out
).success(
fn=on_success, inputs=None, outputs=status
).failure(
fn=on_failure, inputs=None, outputs=status
)
The gr.on() function
Use gr.on() to trigger a function from multiple events:
import gradio as gr
def process(text):
return text.upper()
with gr.Blocks() as demo:
textbox = gr.Textbox()
button = gr.Button("Submit")
output = gr.Textbox()
# Same function triggered by both events
gr.on(
triggers=[button.click, textbox.submit],
fn=process,
inputs=textbox,
outputs=output
)
This is more efficient than setting up separate listeners - it creates only one API endpoint.
Event parameters
Controlling behavior
button.click(
fn=process,
inputs=inp,
outputs=out,
# Control queueing
queue=True, # Use the queue (default)
concurrency_limit=3, # Max 3 simultaneous executions
# Control trigger behavior
trigger_mode="once", # "once", "multiple", or "always_last"
# Display options
show_progress="full", # "full", "minimal", or "hidden"
scroll_to_output=True, # Auto-scroll to output
# API options
api_name="process_text", # Custom endpoint name
api_visibility="public" # "public", "private", or "undocumented"
)
Trigger modes
- “once” (default): Prevents new submissions while one is running
- “multiple”: Allows unlimited simultaneous submissions
- “always_last”: Queues the most recent submission, cancelling intermediate ones
import gradio as gr
import time
def slow_process(x):
time.sleep(3)
return x * 2
with gr.Blocks() as demo:
inp = gr.Number()
out = gr.Number()
btn = gr.Button("Process")
btn.click(
fn=slow_process,
inputs=inp,
outputs=out,
trigger_mode="always_last" # Always process the latest value
)
Cancelling events
Cancel running events when a new event starts:
import gradio as gr
import time
def long_process(x):
for i in range(10):
time.sleep(1)
yield f"Step {i}: {x}"
with gr.Blocks() as demo:
inp = gr.Textbox()
out = gr.Textbox()
start_btn = gr.Button("Start")
stop_btn = gr.Button("Stop")
click_event = start_btn.click(fn=long_process, inputs=inp, outputs=out)
# Clicking stop cancels the running event
stop_btn.click(fn=None, inputs=None, outputs=None, cancels=[click_event])
Preprocessing and postprocessing
Control how data flows through events:
button.click(
fn=process,
inputs=image,
outputs=result,
preprocess=True, # Convert image to expected format before fn
postprocess=True # Convert fn output for display
)
Set to False to work with raw component data:
# Get base64 image string instead of PIL Image
button.click(
fn=process_base64,
inputs=image,
outputs=result,
preprocess=False # Skip conversion to PIL
)
Generator functions
Use generator functions for streaming outputs:
import gradio as gr
import time
def stream_data(text):
for word in text.split():
time.sleep(0.5)
yield word
with gr.Blocks() as demo:
inp = gr.Textbox()
out = gr.Textbox()
btn = gr.Button("Stream")
btn.click(fn=stream_data, inputs=inp, outputs=out)
Outputs update in real-time as the generator yields values.
JavaScript events
Run JavaScript before or after Python functions:
import gradio as gr
with gr.Blocks() as demo:
inp = gr.Textbox()
out = gr.Textbox()
btn = gr.Button("Submit")
btn.click(
fn=lambda x: x.upper(),
inputs=inp,
outputs=out,
js="() => alert('Processing started!')"
)
Load events
Run functions when the page loads:
import gradio as gr
import datetime
def get_time():
return f"Page loaded at {datetime.datetime.now()}"
with gr.Blocks() as demo:
output = gr.Textbox()
demo.load(fn=get_time, inputs=None, outputs=output)
Component-specific events
Different components support different events:
- Button:
click
- Textbox:
change, input, submit, focus, blur
- Slider:
change, release
- File:
upload, delete, download, change
- Image:
select, change, clear, upload
- Chatbot:
change, select, like, retry, undo, clear
- Gallery:
select, change
- Dataframe:
select, change, input
Check each component’s documentation for its supported events.
Event best practices
Performance: Use gr.on() instead of multiple individual listeners when the same function responds to multiple events.
Responsiveness: Use show_progress="minimal" or "hidden" for fast operations to reduce visual clutter.
State isolation: Remember that State components are session-specific. Different users don’t share state values.
Queueing: Long-running or generator functions require the queue to be enabled (it’s enabled by default).
See also
- Interface - High-level event handling
- Blocks - Advanced event patterns
- Components - Which events each component supports
- State - Managing persistent data across events