Gradio HTML component with javascript code don't work

I’m trying to integrate HTML file (which contains javascript function) to gradio HTML component (gr.HTML) and it seems not to work together:

Gradio app:

import gradio as gr

with open("test.html") as f:
    lines = f.readlines()

with gr.Blocks() as demo:   
    input_mic = gr.HTML(lines)
    out_text  = gr.Textbox()

if __name__ == "__main__":   
    demo.launch()

test.html file:

<html>
  <body>

      <script type = "text/JavaScript">
        function test() {
          document.getElementById('demo').innerHTML = "Hello"
          }
      </script>

    <h1>My First JavaScript</h1>
    <button type="testButton" onclick="test()"> Start </button>

    <p id="demo"></p>

  </body>
</html>

When I run test.html it works fine (after clicking on “start” I can see “Hello” in demo id

The HTML seems weird (the button doesn’t look like a button):
image

And when I click on “start” I’m getting an error on the console:
Uncaught ReferenceError: test is not defined at HTMLButtonElement.onclick

How can I integrate the HTML file (with js) to gradio gr.HTML element ?

1 Like

hello @laro1

You can’t load scripts via gr.HTML, but you can run a JavaScript function on page load and thus set your JavaScript code to globalThis, thus visible to the entire page


import gradio as gr

html = """
<html>
  <body>
    <h1>My First JavaScript</h1>
    <button type="testButton" onclick="testFn()"> Start </button>
    <p id="demo"></p>

  </body>
</html>
"""

scripts = """
async () => {
   // set testFn() function on globalThis, so you html onlclick can access it
    globalThis.testFn = () => {
      document.getElementById('demo').innerHTML = "Hello"
    }
}
"""

with gr.Blocks() as demo:   
    input_mic = gr.HTML(html)
    out_text  = gr.Textbox()
    # run script function on load,
    demo.load(None,None,None,_js=scripts)

if __name__ == "__main__":   
    demo.launch()

2 Likes

Ok cool, but what if the js script needs external “script src=” references?

hi @MaxHype , I strongly recommend loading ESM modules, here is an example with two options

import gradio as gr

html = """
<html>
  <body>
    <h1>My First JavaScript</h1>
    <button type="testButton" onclick="testFn()"> Start </button>
    <p id="demo"></p>

  </body>
</html>
"""

scripts = """
async () => {
    // set testFn() function on globalThis, so you html onlclick can access it
    // const d3 = await import("https://cdn.jsdelivr.net/npm/d3@7/+esm");
    // globalThis.d3 = d3;
    // or
    const script = document.createElement("script");
    script.onload = () =>  console.log("d3 loaded") ;
    script.src = "https://cdn.jsdelivr.net/npm/d3@7";
    document.head.appendChild(script)

    globalThis.testFn = () => {
      document.getElementById('demo').innerHTML = "Hello"
    }
}
"""

with gr.Blocks() as demo:   
    input_mic = gr.HTML(html)
    out_text  = gr.Textbox()
    # run script function on load,
    demo.load(None,None,None,_js=scripts)

demo.launch()
2 Likes

Awesome, thank you @radames
I’ll try this asap!

1 Like