How to dispatch JS events properly in Gradio app?

Hi friends,

I’m new to Gradio, and I’m building an app with the layout of 2 columns:

  • The left column is a chatbot
  • The right one is like a glossary

The workflow is when a user chats with the bot, they can highlight text and click on a floating “Show” button to show the selected term in the glossary.

My trouble is when the “Show” button clicked, I want to invoke a Python function with the selected term passed in to handle some logic before returning the output to be attached to the glossary. I don’t know how to implement this properly.

The following code is what I’ve tried so far, it does capture the highlighted text, but clicking the “Show” button doesn’t do anything while I expect it should dispatch some events to simulate Gradio events, hence triggering handlers.

with gr.Blocks() as demo:
    with gr.Row():
        with gr.Column(scale=3):
            chatbot = gr.Chatbot(
                type="messages"
            )
            state = gr.State(value=[])
            txt = gr.Textbox(
                placeholder="Type your answer here…",
                visible=True
            )
            demo.load(init_chat, inputs=None, outputs=[chatbot, state])
            txt.submit(generate_chat_completion, inputs=[txt, state], outputs=[chatbot, state, txt])

        with gr.Column(scale=1):
            glossary = gr.Markdown("Glossary will appear here...")

    selected_term = gr.Textbox(visible=False, elem_id="selected_term")
    selected_term.submit(fn=show_term, inputs=selected_term, outputs=glossary)

    js_script = """
    async () => {
        globalThis.setupShowButton = () => {
            // Create the floating button and attach to body
            if (!document.getElementById("show-btn")) {
                const showBtn = document.createElement("button");
                showBtn.id = "show-btn";
                showBtn.textContent = "Show";
                showBtn.style.display = "none";
                showBtn.style.position = "absolute";
                showBtn.style.zIndex = "999999";
                showBtn.style.background = "#2563eb";
                document.body.appendChild(showBtn);

                showBtn.addEventListener("click", () => {
                    const term = showBtn.getAttribute("data-selection");
                    const textbox = document.querySelector('#selected_term');
                    if (textbox) {
                        textbox.value = term;
                        const inputEvent = new Event("input", { bubbles: true });
                        textbox.dispatchEvent(inputEvent);

                        const keyboardEvent = new KeyboardEvent("keydown", {
                            bubbles: true,
                            cancelable: true,
                            key: "Enter",
                            code: "Enter"
                        });
                        textbox.dispatchEvent(keyboardEvent);
                        showBtn.style.display = "none";
                    }
                });
            }

            const showBtn = document.getElementById("show-btn");

            document.addEventListener("mouseup", function () {
                const selection = window.getSelection().toString().trim();
                if (!selection) {
                    showBtn.style.display = "none";
                    return;
                }
                try {
                    const range = window.getSelection().getRangeAt(0);
                    const rect = range.getBoundingClientRect();
                    showBtn.style.display = "block";
                    showBtn.setAttribute("data-selection", selection);
                } catch (err) {
                    console.warn("Range error:", err);
                }
            });
        };
        setTimeout(globalThis.setupShowButton, 100);
    }
    """
    demo.load(None, None, None, js=js_script)

return demo

Any help would be much appreciated. Thanks so much for your support!

1 Like

Gradio is convenient, but it’s not very flexible…

There is a dedicated Gradio question channel on HF Discord, so if you can ask your questions there, I recommend that.

1 Like