Skip to main content
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.
Learn more about themes in the Theming guide.

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.

Adding meta tags for social sharing

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

1

Start with themes

Use Gradio’s theming system before writing custom CSS. Themes are maintainable and work across Gradio versions.
2

Use elem_id and elem_classes

Target specific components with elem_id and elem_classes instead of relying on Gradio’s internal class names.
3

Test across browsers

Custom CSS and JavaScript may behave differently in different browsers. Test thoroughly.
4

Avoid breaking changes

Gradio’s internal DOM structure may change between versions. Use stable APIs like elem_id and avoid deeply nested selectors.
5

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: