Customizing your demo with CSS and Javascript
Gradio allows you to customize your demo in several ways. You can customize the layout of your demo, add custom HTML, and add custom theming as well. This tutorial will go beyond that and walk you through how to add custom CSS and JavaScript code to your demo in order to add custom styling, animations, custom UI functionality, analytics, and more.
Adding custom CSS to your demo
Gradio themes are the easiest way to customize the look and feel of your app. You can choose from a variety of themes, or create your own. To do so, pass the
theme=
kwarg to the
Blocks
constructor. For example:
with gr.Blocks(theme=gr.themes.Glass()):
...
Gradio comes with a set of prebuilt themes which you can load from
gr.themes.*
. You can extend these themes or create your own themes from scratch - see the
Theming guide
for more details.
For additional styling ability, you can pass any CSS to your app using the
css=
kwarg. You can either the filepath to a CSS file, or a string of CSS code.
Warning : The use of query selectors in custom JS and CSS is not guaranteed to work across Gradio versions as the Gradio HTML DOM may change. We recommend using query selectors sparingly.
The base class for the Gradio app is
gradio-container
, so here's an example that changes the background color of the Gradio app:
with gr.Blocks(css=".gradio-container {background-color: red}") as demo:
...
If you'd like to reference external files in your css, preface the file path (which can be a relative or absolute path) with
"file="
, for example:
with gr.Blocks(css=".gradio-container {background: url('file=clouds.jpg')}") as demo:
...
Note: By default, files in the host machine are not accessible to users running the Gradio app. As a result, you should make sure that any referenced files (such as
clouds.jpg
here) are either URLs or allowed via the
allow_list
parameter in
launch()
. Read more in our
section on Security and File Access
.
The
elem_id
and
elem_classes
Arguments
You can
elem_id
to add an HTML element
id
to any component, and
elem_classes
to add a class or list of classes. This will allow you to select elements more easily with CSS. This approach is also more likely to be stable across Gradio versions as built-in class names or ids may change (however, as mentioned in the warning above, we cannot guarantee complete compatibility between Gradio versions if you use custom CSS as the DOM elements may themselves change).
css = """
#warning {background-color: #FFCCCB}
.feedback textarea {font-size: 24px !important}
with gr.Blocks(css=css) as demo:
box1 = gr.Textbox(value="Good Job", elem_classes="feedback")
box2 = gr.Textbox(value="Failure", elem_id="warning", elem_classes="feedback")
The CSS
#warning
ruleset will only target the second Textbox, while the
.feedback
ruleset will target both. Note that when targeting classes, you might need to put the
!important
selector to override the default Gradio styles.
Adding custom JavaScript to your demo
There are 3 ways to add javascript code to your Gradio demo:
js
parameter of the
Blocks
or
Interface
initializer. This will run the JavaScript code when the demo is first loaded.
Below is an example of adding custom js to show an animated welcome message when the demo first loads.
import gradio as gr
def welcome(name):
return f"Welcome to Gradio, {name}!"
js = """
function createGradioAnimation() {
var container = document.createElement('div');
container.id = 'gradio-animation';
container.style.fontSize = '2em';
container.style.fontWeight = 'bold';
container.style.textAlign = 'center';
container.style.marginBottom = '20px';
var text = 'Welcome to Gradio!';
for (var i = 0; i < text.length; i++) {
(function(i){
setTimeout(function(){
var letter = document.createElement('span');
letter.style.opacity = '0';
letter.style.transition = 'opacity 0.5s';
letter.innerText = text[i];
container.appendChild(letter);
setTimeout(function() {
letter.style.opacity = '1';
}, 50);
}, i * 250);
})(i);
var gradioContainer = document.querySelector('.gradio-container');
gradioContainer.insertBefore(container, gradioContainer.firstChild);
return 'Animation created';
with gr.Blocks(js=js) as demo:
inp = gr.Textbox(placeholder="What is your name?")
out = gr.Textbox()
inp.change(welcome, inp, out)
demo.launch()
Note: You can also supply your custom js code as a file path. For example, if you have a file called
custom.js
in the same directory as your Python script, you can add it to your demo like so:
with gr.Blocks(js="custom.js") as demo:
. Same goes for
Interface
(ex:
gr.Interface(..., js="custom.js")
).
Blocks
and event listeners, events have a
js
argument that can take a JavaScript function as a string and treat it just like a Python event listener function. You can pass both a JavaScript function and a Python function (in which case the JavaScript function is run first) or only Javascript (and set the Python
fn
to
None
). Take a look at the code below:
import gradio as gr
blocks = gr.Blocks()
with blocks as demo:
subject = gr.Textbox(placeholder="subject")
verb = gr.Radio(["ate", "loved", "hated"])
object = gr.Textbox(placeholder="object")
with gr.Row():
btn = gr.Button("Create sentence.")
reverse_btn = gr.Button("Reverse sentence.")
foo_bar_btn = gr.Button("Append foo")
reverse_then_to_the_server_btn = gr.Button(
"Reverse sentence and send to server."
def sentence_maker(w1, w2, w3):
return f"{w1} {w2} {w3}"
output1 = gr.Textbox(label="output 1")
output2 = gr.Textbox(label="verb")
output3 = gr.Textbox(label="verb reversed")
output4 = gr.Textbox(label="front end process and then send to backend")
btn.click(sentence_maker, [subject, verb, object], output1)
reverse_btn.click(
None, [subject, verb, object], output2, js="(s, v, o) => o + ' ' + v + ' ' + s"
verb.change(lambda x: x, verb, output3, js="(x) => [...x].reverse().join('')")
foo_bar_btn.click(None, [], subject, js="(x) => x + ' foo'")
reverse_then_to_the_server_btn.click(
sentence_maker,
[subject, verb, object],
output4,
js="(s, v, o) => [s, v, o].map(x => [...x].reverse().join(''))",
demo.launch()
Lastly, you can add JavaScript code to the head
param of the Blocks
initializer. This will add the code to the head of the HTML document. For example, you can add Google Analytics to your demo like so:
head = f"""
<script async src="https://www.googletagmanager.com/gtag/js?id={google_analytics_tracking_id}"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){{dataLayer.push(arguments);}}
gtag('js', new Date());
gtag('config', '{google_analytics_tracking_id}');
</script>
with gr.Blocks(head=head) as demo:
...demo code...
The head
parameter accepts any HTML tags you would normally insert into the <head>
of a page. For example, you can also include <meta>
tags to head
.
Note that injecting custom HTML can affect browser behavior and compatibility (e.g. keyboard shortcuts). You should test your interface across different browsers and be mindful of how scripts may interact with browser defaults.
Here's an example where pressing Shift + s
triggers the click
event of a specific Button
component if the browser focus is not on an input component (e.g. Textbox
component):
import gradio as gr
shortcut_js = """
<script>
function shortcuts(e) {
var event = document.all ? window.event : e;
switch (e.target.tagName.toLowerCase()) {
case "input":
case "textarea":
break;
default:
if (e.key.toLowerCase() == "s" && e.shiftKey) {
document.getElementById("my_btn").click();
document.addEventListener('keypress', shortcuts, false);
</script>
with gr.Blocks(head=shortcut_js) as demo:
action_button = gr.Button(value="Name", elem_id="my_btn")
textbox = gr.Textbox()
action_button.click(lambda : "button pressed", None, textbox)
demo.launch()