-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Add ability to add custom buttons to components #12539
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
🪼 branch checks and previews
Install Gradio from this PR pip install https://gradio-pypi-previews.s3.amazonaws.com/b49195284ea2e3008b59c90c1c2579ca8b96a2a3/gradio-6.1.0-py3-none-any.whlInstall Gradio Python Client from this PR pip install "gradio-client @ git+https://github.com/gradio-app/gradio@b49195284ea2e3008b59c90c1c2579ca8b96a2a3#subdirectory=client/python"Install Gradio JS Client from this PR npm install https://gradio-npm-previews.s3.amazonaws.com/b49195284ea2e3008b59c90c1c2579ca8b96a2a3/gradio-client-2.0.0.tgz |
🦄 change detectedThis Pull Request includes changes to the following packages.
✅ Changeset approved by @abidlabs
|
aliabid94
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Neat API, worked well in my tests! Why is it not present in every component? Feel like it should be as ubiquitous as label=, not this subset of components.
Also think it could be wrapped up more neatly in the frontend in a reusable svelte component, seems like currently every frontend component is recreating this <IconButtonWrapper> with copy logic and looping through the other buttons.
Another nit, and may not be this PRs fault, but custom button borders look funny when in a form next to other components:

Good point! Will implement this and fix the other issues on Monday |
freddyaboulton
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great @abidlabs ! Agree with Ali's comments and left a few more.
js/core/src/Blocks.svelte
Outdated
| register: app_tree.register_component.bind(app_tree), | ||
| dispatcher: gradio_event_dispatcher | ||
| dispatcher: gradio_event_dispatcher, | ||
| dispatch_to: dispatch_to_target |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we need a separate method for dispatching. Instead of doing dispatch_to inside each component, we can do gradio.dispatch("custom_button_click", {id: ..., ...}) and do the dispatch_to logic in the gradio_event_dispatcher function
js/textbox/Index.svelte
Outdated
| let _props = $props(); | ||
| const gradio = new Gradio<TextboxEvents, TextboxProps>(_props); | ||
| const gradio = new Gradio< | ||
| TextboxEvents | "custom_button_click", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Type checking dispabled right now in the frontend but I think we should just add custom_button_click to each events class
js/atoms/src/CustomButton.svelte
Outdated
| @@ -0,0 +1,59 @@ | |||
| <script lang="ts"> | |||
| import { Image } from "@gradio/image/shared"; | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this introduces a circular dependency. @gradio/image depends on gradio/atoms and gradio/atoms depends on gradio/image. Not sure how the build is passing right now, but I think having this circular dependency will cause problems down the line eventually.
| object-fit: contain; | ||
| } | ||
| .custom-button-label { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
Thanks @freddyaboulton as well for the feedback! I'll add some docs for this as well. |
Moved most of the duplicated code into the
I'm not sure how to fix it actually because it should only be applied when the component is a form and its not at the the "top" of the form, otherwise you have a duplicated, thicker border. I'll open a separate issue (as this was preexisting)
Thanks for the suggestion! Both of these fixed in: 8dd9e01
I just removed the icon rendering. Emojis work better anyways. Fixed in 8ba76cb Adding it now as a parameter in all of the other component |
|
Should be good to merge once CI is green. Will merge later tonight if there are no objections. |
|
Amazing! I was using patches via js for this before |




We now support using regular old
gr.Buttoninstances as custom buttons inside components that have thebuttonsprop. These buttons appear in the top right toolbar for the component, next to standard icon buttons, and you can attach python or js events to thesegr.Button's, which are triggered when the buttons in the toolbars are clicked. For example:produces this:
Screen.Recording.2025-12-11.at.2.21.47.PM.mov
For a more complete example, see:
demo/textbox_custom_buttons/run.py, which shows you can also attachjsevents like what you'd expect.Screen.Recording.2025-12-11.at.2.23.32.PM.mov
This works for all components except for Dataframe and ImageEditor since those components need significant refactoring first I believe. Will handle them in a follow up PR.
Closes: #11878
AI disclosure: I implemented this mostly by hand for
gr.Textboxand then used AI to extend to other components. I spot tested a variety of components to ensure behavior is as expected.