Gradio gives you several ways to customize the appearance and behavior of your app beyond the built-in themes and components. You can add custom CSS for styling, JavaScript for client-side functionality, and HTML elements for analytics or meta tags.
Adding custom CSS
Gradio themes are the easiest way to customize your app’s look. You can choose from built-in themes or create your own:
import gradio as gr
with gr.Blocks() as demo:
# Your components here
pass
demo.launch(theme=gr.themes.Glass())
Gradio includes several prebuilt themes accessible via gr.themes.*. You can extend these or create entirely new themes.
Adding custom CSS strings
For additional styling, pass CSS as a string to the css parameter in launch():
import gradio as gr
with gr.Blocks() as demo:
textbox = gr.Textbox(label="Input")
button = gr.Button("Submit")
demo.launch(css="""
.gradio-container {
background-color: #f0f0f0;
}
button {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
color: white;
}
""")
The base class for the Gradio app is gradio-container, which you can use to style the entire app.
Loading CSS from files
You can also load CSS from external files using the css_paths parameter:
import gradio as gr
from pathlib import Path
with gr.Blocks() as demo:
# Your components here
pass
demo.launch(css_paths=[Path("./styles/custom.css"), Path("./styles/animations.css")])
Referencing external files
If your CSS references external files (like images), prefix the file path with "/gradio_api/file=":
import gradio as gr
with gr.Blocks() as demo:
# Your components here
pass
demo.launch(css="""
.gradio-container {
background: url('/gradio_api/file=clouds.jpg');
background-size: cover;
}
""")
By default, most files on the host machine are not accessible to users. Make sure referenced files (like clouds.jpg) are either URLs or allowed paths.
Using elem_id and elem_classes
Every Gradio component accepts elem_id and elem_classes parameters to help you target specific elements with CSS:
elem_id: Adds an HTML id attribute (must be unique)
elem_classes: Adds one or more HTML class names (can be a string or list)
import gradio as gr
css = """
#warning {
background-color: #FFCCCB;
border: 2px solid red;
}
.feedback textarea {
font-size: 24px !important;
font-weight: bold;
}
"""
with gr.Blocks() as demo:
box1 = gr.Textbox(value="Good Job", elem_classes="feedback")
box2 = gr.Textbox(
value="Needs Improvement",
elem_id="warning",
elem_classes="feedback"
)
demo.launch(css=css)
The CSS:
#warning targets only the second textbox (using its unique ID)
.feedback targets both textboxes (using their shared class)
Tip: When targeting classes, you may need to use !important to override Gradio’s default styles.
Using query selectors with Gradio’s internal HTML elements is not guaranteed to work across versions, as the DOM structure may change. Use elem_id and elem_classes for stability.
Adding custom JavaScript
There are three ways to add JavaScript to your Gradio app:
1. JavaScript on page load
Run JavaScript when the demo first loads using the js parameter:
import gradio as gr
js_code = """
() => {
console.log('Gradio app loaded!');
alert('Welcome to my Gradio app!');
// Add some animation
const container = document.querySelector('.gradio-container');
container.style.animation = 'fadeIn 1s';
}
"""
with gr.Blocks() as demo:
gr.Markdown("# Welcome!")
gr.Textbox(label="Input")
demo.launch(js=js_code)
2. JavaScript event handlers
Run JavaScript when an event is triggered using the js parameter on event listeners:
import gradio as gr
with gr.Blocks() as demo:
name_box = gr.Textbox(label="Name")
greeting_box = gr.Textbox(label="Greeting")
button = gr.Button("Greet")
# JavaScript runs first (client-side)
button.click(
fn=lambda x: f"Hello {x}!", # Then Python runs (server-side)
inputs=name_box,
outputs=greeting_box,
js="""(name) => {
console.log('Button clicked for:', name);
return name.toUpperCase(); // Modify input before sending to Python
}"""
)
demo.launch()
You can also use JavaScript without a Python function:
import gradio as gr
with gr.Blocks() as demo:
textbox = gr.Textbox()
button = gr.Button("Click me")
# Only JavaScript, no Python function
button.click(
fn=None, # No Python function
inputs=textbox,
outputs=textbox,
js="""(text) => {
return text.split('').reverse().join('');
}"""
)
demo.launch()
3. Adding code to the HTML head
Add scripts, meta tags, or other HTML elements to the page <head> using the head parameter:
import gradio as gr
# Example: Add Google Analytics
google_analytics_id = "G-XXXXXXXXXX"
head = f"""
<script async src="https://www.googletagmanager.com/gtag/js?id={google_analytics_id}"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){{dataLayer.push(arguments);}}
gtag('js', new Date());
gtag('config', '{google_analytics_id}');
</script>
"""
with gr.Blocks() as demo:
gr.HTML("<h1>My App</h1>")
gr.Textbox(label="Input")
demo.launch(head=head)
The head parameter accepts any HTML tags you would normally put in the <head> section.
You can customize how your app appears when shared on social media:
import gradio as gr
custom_head = """
<!-- HTML Meta Tags -->
<title>My Awesome Gradio App</title>
<meta name="description" content="An AI-powered tool for image generation">
<!-- Facebook Meta Tags -->
<meta property="og:url" content="https://example.com">
<meta property="og:type" content="website">
<meta property="og:title" content="My Awesome Gradio App">
<meta property="og:description" content="An AI-powered tool for image generation">
<meta property="og:image" content="https://example.com/preview.jpg">
<!-- Twitter Meta Tags -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:creator" content="@myusername">
<meta name="twitter:title" content="My Awesome Gradio App">
<meta name="twitter:description" content="An AI-powered tool for image generation">
<meta name="twitter:image" content="https://example.com/preview.jpg">
<meta property="twitter:domain" content="example.com">
<meta property="twitter:url" content="https://example.com">
"""
with gr.Blocks() as demo:
gr.Markdown("# My Awesome App")
# Your components here
demo.launch(head=custom_head)
Example: Custom keyboard shortcuts
Here’s a complete example that adds keyboard shortcuts to your app:
import gradio as gr
shortcut_js = """
<script>
function handleKeyPress(e) {
// Don't trigger shortcuts when typing in input fields
const tagName = e.target.tagName.toLowerCase();
if (tagName === 'input' || tagName === 'textarea') {
return;
}
// Shift + S triggers the submit button
if (e.key.toLowerCase() === 's' && e.shiftKey) {
document.getElementById('submit_btn').click();
}
// Shift + C clears the textbox
if (e.key.toLowerCase() === 'c' && e.shiftKey) {
document.getElementById('clear_btn').click();
}
}
document.addEventListener('keypress', handleKeyPress, false);
</script>
"""
with gr.Blocks() as demo:
gr.Markdown("""
# Keyboard Shortcuts Demo
- **Shift + S**: Submit
- **Shift + C**: Clear
""")
textbox = gr.Textbox(label="Input")
output = gr.Textbox(label="Output")
with gr.Row():
submit_btn = gr.Button("Submit", elem_id="submit_btn")
clear_btn = gr.Button("Clear", elem_id="clear_btn")
submit_btn.click(
lambda x: f"You submitted: {x}",
inputs=textbox,
outputs=output
)
clear_btn.click(
lambda: "",
inputs=None,
outputs=textbox
)
demo.launch(head=shortcut_js)
Accessibility note: Custom JavaScript can affect browser behavior and accessibility. Test your interface across different browsers and be mindful of how scripts may interact with:
- Screen readers
- Browser extensions
- Default keyboard shortcuts
- Focus management
Best practices
Start with themes
Use Gradio’s theming system before writing custom CSS. Themes are maintainable and work across Gradio versions.
Use elem_id and elem_classes
Target specific components with elem_id and elem_classes instead of relying on Gradio’s internal class names.
Test across browsers
Custom CSS and JavaScript may behave differently in different browsers. Test thoroughly.
Avoid breaking changes
Gradio’s internal DOM structure may change between versions. Use stable APIs like elem_id and avoid deeply nested selectors.
Validate file paths
When referencing external files, ensure they’re in allowed paths or are public URLs.
Next steps
Now that you know how to customize your app’s appearance and behavior: