Introducing FastRTC, a new way to build real-time AI apps
Read MoreIntroducing FastRTC, a new way to build real-time AI apps
Read MoreGradio allows you to run certain "simple" functions directly in the browser by setting js=True
in your event listeners. This will automatically convert your Python code into JavaSCript, which significantly improves the responsiveness of your app by avoiding a round trip to the server for simple UI updates.
The difference in responsiveness is most noticeable on hosted applications (like Hugging Face Spaces), when the server is under heavy load, with high-latency connections, or when many users are accessing the app simultaneously.
Client side functions are ideal for updating component properties (like visibility, placeholders, interactive state, or styling).
Here's a basic example:
import gradio as gr
with gr.Blocks() as demo:
with gr.Row() as row:
btn = gr.Button("Hide this row")
# This function runs in the browser without a server roundtrip
btn.click(
lambda: gr.Row(visible=False),
None,
row,
js=True
)
demo.launch()
Client side functions have some important restrictions:
Here are some functions that will work with js=True
:
# Simple property updates
lambda: gr.Textbox(lines=4)
# Multiple component updates
lambda: [gr.Textbox(lines=4), gr.Button(interactive=False)]
# Using gr.update() for property changes
lambda: gr.update(visible=True, interactive=False)
We are working to increase the space of functions that can be transpiled to JavaScript so that they can be run in the browser. Follow the Groovy library for more info.
Here's a more complete example showing how client side functions can improve the user experience:
"""
This is a simple todo list app that allows you to edit tasks and mark tasks as complete.
All actions are performed on the client side.
"""
import gradio as gr
tasks = ["Get a job", "Marry rich", "", "", "", ""]
textboxes = []
buttons = []
with gr.Blocks() as demo:
with gr.Row():
with gr.Column(scale=3):
gr.Markdown("# A Simple Interactive Todo List")
with gr.Column(scale=2):
with gr.Row():
freeze_button = gr.Button("Freeze tasks", variant="stop")
edit_button = gr.Button("Edit tasks")
for i in range(6):
with gr.Row() as r:
t = gr.Textbox(tasks[i], placeholder="Enter a task", show_label=False, container=False, scale=7, interactive=True)
b = gr.Button("✔️", interactive=bool(tasks[i]), variant="primary" if tasks[i] else "secondary")
textboxes.append(t)
buttons.append(b)
t.change(lambda : gr.Button(interactive=True, variant="primary"), None, b, js=True)
b.click(lambda : gr.Row(visible=False), None, r, js=True)
freeze_button.click(lambda : [gr.Textbox(interactive=False), gr.Textbox(interactive=False), gr.Textbox(interactive=False), gr.Textbox(interactive=False), gr.Textbox(interactive=False), gr.Textbox(interactive=False)], None, textboxes, js=True)
edit_button.click(lambda : [gr.Textbox(interactive=True), gr.Textbox(interactive=True), gr.Textbox(interactive=True), gr.Textbox(interactive=True), gr.Textbox(interactive=True), gr.Textbox(interactive=True)], None, textboxes, js=True)
freeze_button.click(lambda : [gr.Button(visible=False), gr.Button(visible=False), gr.Button(visible=False), gr.Button(visible=False), gr.Button(visible=False), gr.Button(visible=False)], None, buttons, js=True)
edit_button.click(lambda : [gr.Button(visible=True), gr.Button(visible=True), gr.Button(visible=True), gr.Button(visible=True), gr.Button(visible=True), gr.Button(visible=True)], None, buttons, js=True)
demo.launch()
When you set js=True
, Gradio:
Transpiles your Python function to JavaScript
Runs the function directly in the browser
Still sends the request to the server (for consistency and to handle any side effects)
This provides immediate visual feedback while ensuring your application state remains consistent.