Repository: gradio-app/gradio
Pull request: Add `interactive=False` mode to `gr.Button`
Like other components, `gr.Button` should support a disabled mode if `interactive=False` is set. Note that unlike other components, `gr.Button()`'s interactive state should not be inferred based on whether it is an input component or not, so it needs to be explicitly set to `interactive=False` in order to be disabled. 

The current way of designating the disabled state is to show a "can't-click" cursor and show no color change when a user hovers over the button. Open to feedback on this, though I wanted to keep it pretty simple so as to not need new css variables, etc. 

Fixes: #3084

![Recording 2023-02-21 at 10 56 39 (1)](https://user-images.githubusercontent.com/1778297/220411102-08a57450-7482-416b-9e4f-70ef5befc548.gif)




Problem statement:
No `interactive` option for `gr.Button()`
- [x] I have searched to see if a similar issue already exists.


**Is your feature request related to a problem? Please describe.**  
I want to disable a button, but `gr.Button` has no `interactive` property. I have to hide it instead

**Describe the solution you'd like**  
Add `interactive` to `gr.Button` like there is for `gr.Dropdown`, `gr.Textbox`, `gr.Slider`, `gr.Checkbox`...

**Additional context**  
N/A

Hints from issue discussion:

Commit message: formatting

Patch to review:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cf6381711d..06c87f6da0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,8 @@
 
 ## New Features:
 - Updated image upload component to accept all image formats, including lossless formats like .webp by [@fienestar](https://github.com/fienestar) in [PR 3225](https://github.com/gradio-app/gradio/pull/3225)
+- Adds a disabled mode to the `gr.Button` component by setting `interactive=False` by [@abidlabs](https://github.com/abidlabs) in [PR 3266](https://github.com/gradio-app/gradio/pull/3266)
+
 
 ## Bug Fixes:
 - Ensure `mirror_webcam` is always respected by [@pngwn](https://github.com/pngwn) in [PR 3245](https://github.com/gradio-app/gradio/pull/3245)
diff --git a/gradio/components.py b/gradio/components.py
index db576620ce..a6cfffaab2 100644
--- a/gradio/components.py
+++ b/gradio/components.py
@@ -2909,6 +2909,7 @@ def __init__(
         *,
         variant: str = "secondary",
         visible: bool = True,
+        interactive: bool = True,
         elem_id: str | None = None,
         **kwargs,
     ):
@@ -2920,7 +2921,12 @@ def __init__(
             elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
         """
         IOComponent.__init__(
-            self, visible=visible, elem_id=elem_id, value=value, **kwargs
+            self,
+            visible=visible,
+            elem_id=elem_id,
+            value=value,
+            interactive=interactive,
+            **kwargs,
         )
         self.variant = variant
 
@@ -2928,6 +2934,7 @@ def get_config(self):
         return {
             "value": self.value,
             "variant": self.variant,
+            "interactive": self.interactive,
             **Component.get_config(self),
         }
 
@@ -2936,11 +2943,13 @@ def update(
         value: str | Literal[_Keywords.NO_VALUE] | None = _Keywords.NO_VALUE,
         variant: str | None = None,
         visible: bool | None = None,
+        interactive: bool | None = None,
     ):
         return {
             "variant": variant,
             "visible": visible,
             "value": value,
+            "interactive": interactive,
             "__type__": "update",
         }
 
diff --git a/gradio/test_data/blocks_configs.py b/gradio/test_data/blocks_configs.py
index 11dfa3a8da..3c061f4fc6 100644
--- a/gradio/test_data/blocks_configs.py
+++ b/gradio/test_data/blocks_configs.py
@@ -68,6 +68,7 @@
             "props": {
                 "value": "Run",
                 "variant": "secondary",
+                "interactive": True,
                 "name": "button",
                 "visible": True,
                 "style": {},
@@ -115,6 +116,7 @@
                 "value": "Run",
                 "variant": "secondary",
                 "name": "button",
+                "interactive": True,
                 "visible": True,
                 "style": {},
             },
@@ -301,6 +303,7 @@
             "props": {
                 "value": "Run",
                 "variant": "secondary",
+                "interactive": True,
                 "name": "button",
                 "visible": True,
                 "style": {},
@@ -347,6 +350,7 @@
             "props": {
                 "value": "Run",
                 "variant": "secondary",
+                "interactive": True,
                 "name": "button",
                 "visible": True,
                 "style": {},
@@ -538,6 +542,7 @@
             "props": {
                 "value": "Run",
                 "name": "button",
+                "interactive": True,
                 "css": {"background-color": "red", "--hover-color": "orange"},
                 "variant": "secondary",
             },
@@ -583,6 +588,7 @@
             "type": "button",
             "props": {
                 "value": "Run",
+                "interactive": True,
                 "name": "button",
                 "style": {},
                 "variant": "secondary",
diff --git a/ui/packages/app/src/components/Button/Button.svelte b/ui/packages/app/src/components/Button/Button.svelte
index e81f8b2688..ebae71896c 100644
--- a/ui/packages/app/src/components/Button/Button.svelte
+++ b/ui/packages/app/src/components/Button/Button.svelte
@@ -8,8 +8,16 @@
 	export let visible: boolean = true;
 	export let value: string;
 	export let variant: "primary" | "secondary" = "primary";
+	export let mode: "static" | "dynamic";
 </script>
 
-<Button {variant} {elem_id} {style} {visible} on:click>
+<Button
+	{variant}
+	{elem_id}
+	{style}
+	{visible}
+	disabled={mode === "static"}
+	on:click
+>
 	{$_(value)}
 </Button>
diff --git a/ui/packages/app/src/components/Button/index.ts b/ui/packages/app/src/components/Button/index.ts
index a220b88c2a..82c96b9120 100644
--- a/ui/packages/app/src/components/Button/index.ts
+++ b/ui/packages/app/src/components/Button/index.ts
@@ -1,5 +1,5 @@
 export { default as Component } from "./Button.svelte";
-export const modes = ["static"];
+export const modes = ["static", "dynamic"];
 
 export const document = (config: Record<string, any>) => ({
 	type: "string",
diff --git a/ui/packages/button/src/Button.svelte b/ui/packages/button/src/Button.svelte
index 9c2b17f2bb..74a9ce1647 100644
--- a/ui/packages/button/src/Button.svelte
+++ b/ui/packages/button/src/Button.svelte
@@ -7,8 +7,11 @@
 	export let visible: boolean = true;
 	export let variant: "primary" | "secondary" | "stop" | "plain" = "secondary";
 	export let size: "sm" | "lg" = "lg";
+	export let disabled: boolean = false;
 
 	$: ({ styles } = get_styles(style, ["full_width"]));
+	console.log("size", size);
+	console.log("disabled", disabled);
 </script>
 
 <button
@@ -17,6 +20,7 @@
 	class="{size} {variant}"
 	style={styles}
 	id={elem_id}
+	{disabled}
 >
 	<slot />
 </button>
@@ -31,10 +35,15 @@
 		text-align: center;
 	}
 
-	button:hover {
+	button:hover,
+	button[disabled] {
 		box-shadow: var(--shadow-drop-lg);
 	}
 
+	button[disabled] {
+		cursor: not-allowed;
+	}
+
 	.hide {
 		display: none;
 	}
@@ -45,7 +54,8 @@
 		color: var(--button-plain-text-color-base);
 	}
 
-	.plain:hover {
+	.plain:hover,
+	.plain[disabled] {
 		border: 1px solid var(--button-plain-border-color-hover);
 		background: var(--button-plain-background-hover);
 		color: var(--button-plain-text-color-hover);
@@ -60,7 +70,8 @@
 		background: var(--button-primary-background-base);
 		color: var(--button-primary-text-color-base);
 	}
-	.primary:hover {
+	.primary:hover,
+	.primary[disabled] {
 		border-color: var(--button-primary-border-color-hover);
 		background: var(--button-primary-background-hover);
 		color: var(--button-primary-text-color-hover);
@@ -78,7 +89,8 @@
 		color: var(--button-secondary-text-color-base);
 	}
 
-	.secondary:hover {
+	.secondary:hover,
+	.secondary[disabled] {
 		border-color: var(--button-secondary-border-color-hover);
 		background: var(--button-secondary-background-hover);
 		color: var(--button-secondary-text-color-hover);
@@ -96,7 +108,8 @@
 		color: var(--button-cancel-text-color-base);
 	}
 
-	.stop:hover {
+	.stop:hover,
+	.stop[disabled] {
 		border-color: var(--button-cancel-border-color-hover);
 		background: var(--button-cancel-background-hover);
 		color: var(--button-cancel-text-color-hover);


Code review comments:
diff_hunk: @@ -8,8 +8,16 @@
 	export let visible: boolean = true;
 	export let value: string;
 	export let variant: "primary" | "secondary" = "primary";
+	export let mode: "static" | "dynamic";
path: ui/packages/app/src/components/Button/Button.svelte
text: @user1:
If we add this, the TypeScript error should go away:

```suggestion
	export let mode: "static" | "dynamic" = "dynamic";
```

diff_hunk: @@ -7,8 +7,11 @@
 	export let visible: boolean = true;
 	export let variant: "primary" | "secondary" | "stop" | "plain" = "secondary";
 	export let size: "sm" | "lg" = "lg";
+	export let disabled: boolean = false;
 
 	$: ({ styles } = get_styles(style, ["full_width"]));
+	console.log("size", size);
+	console.log("disabled", disabled);
path: ui/packages/button/src/Button.svelte
text: @user1:
remove these,