Repository: gradio-app/gradio
Pull request: Add height param to gr.JSON
## Description

I initially implemented `height` as a param but we have a `lines` param in gr.Code, so it makes some sense to keep them fairly consistent. 

I also added the lines param description in gr.Code that was missing, and added a tiny css tweak to handle big line numbers.

Closes: #8982

## 🎯 PRs Should Target Issues

Before your create a PR, please check to see if there is [an existing issue](https://github.com/gradio-app/gradio/issues) for this change. If not, please create an issue before you create this PR, unless the fix is very small. 

Not adhering to this guideline will result in the PR being closed. 

## Tests

1. PRs will only be merged if tests pass on CI. To run the tests locally, please set up [your Gradio environment locally](https://github.com/gradio-app/gradio/blob/main/CONTRIBUTING.md) and run the tests: `bash scripts/run_all_tests.sh`

2. You may need to run the linters: `bash scripts/format_backend.sh` and `bash scripts/format_frontend.sh`
  


Problem statement:
The gr.JSON requires the lines parameter.
- [ Yes] I have searched to see if a similar issue already exists.

Is it possible to configure gr.JSON() with lines to ensure that content overflow does not occur? Previously, I tried using gr.Textbox(inputs=gr.JSON()), but doing this loses the interactive functionality of JSON.

Hints from issue discussion:
I think this is fixed in version 4.40.0 - the json component will no longer overflow horizontally or vertically
My current version is already 4.40. Currently, the JSON is too long and automatically adapts to be particularly long (as shown in the first image). However, I would like to restrict it within a specified box size (like Textbox) while retaining the formatted indentation of the JSON for interaction.

![image](https://github.com/user-attachments/assets/1577ddef-691c-4aa6-8e1b-af7e611090c6)

![image](https://github.com/user-attachments/assets/afdbed3c-378b-4a86-a8cf-65579fc80b3a)

Commit message: fix test

Patch to review:
diff --git a/gradio/components/code.py b/gradio/components/code.py
index 0368be1f0d..75eb913816 100644
--- a/gradio/components/code.py
+++ b/gradio/components/code.py
@@ -122,6 +122,7 @@ def __init__(
             elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
             render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
             key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
+            lines: Maximum number of visible lines to show in the code editor. Overflow will be scrollable.
         """
         if language not in Code.languages:
             raise ValueError(f"Language {language} not supported.")
diff --git a/gradio/components/json_component.py b/gradio/components/json_component.py
index 6369838980..739420cea6 100644
--- a/gradio/components/json_component.py
+++ b/gradio/components/json_component.py
@@ -49,6 +49,7 @@ def __init__(
         key: int | str | None = None,
         open: bool = False,
         show_indices: bool = False,
+        lines: int | None = None,
     ):
         """
         Parameters:
@@ -67,6 +68,7 @@ def __init__(
             key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
             open: If True, all JSON nodes will be expanded when rendered. By default, node levels deeper than 3 are collapsed.
             show_indices: Whether to show numerical indices when displaying the elements of a list within the JSON object.
+            lines: Maximum number of visible lines to show in the component. Overflow will be scrollable.
         """
         super().__init__(
             label=label,
@@ -86,6 +88,7 @@ def __init__(
 
         self.show_indices = show_indices
         self.open = open
+        self.lines = lines
 
     def preprocess(self, payload: dict | list | None) -> dict | list | None:
         """
diff --git a/js/json/Index.svelte b/js/json/Index.svelte
index f7e7f43d8b..e2c0dbf536 100644
--- a/js/json/Index.svelte
+++ b/js/json/Index.svelte
@@ -29,6 +29,7 @@
 	export let open = false;
 	export let theme_mode: "system" | "light" | "dark";
 	export let show_indices: boolean;
+	export let lines: number | undefined;
 
 	$: {
 		if (value !== old_value) {
@@ -47,6 +48,7 @@
 	{scale}
 	{min_width}
 	padding={false}
+	allow_overflow={false}
 >
 	{#if label}
 		<BlockLabel
@@ -65,5 +67,5 @@
 		on:clear_status={() => gradio.dispatch("clear_status", loading_status)}
 	/>
 
-	<JSON {value} {open} {theme_mode} {show_indices} />
+	<JSON {value} {open} {theme_mode} {show_indices} {lines} />
 </Block>
diff --git a/js/json/JSON.stories.svelte b/js/json/JSON.stories.svelte
index 1372fe01e9..f0b488730b 100644
--- a/js/json/JSON.stories.svelte
+++ b/js/json/JSON.stories.svelte
@@ -51,9 +51,10 @@
 />
 
 <Story
-	name="JSON viewed as list"
+	name="JSON viewed as list with line limit"
 	args={{
 		value: SAMPLE_JSON,
-		show_indices: true
+		show_indices: true,
+		lines: 10
 	}}
 />
diff --git a/js/json/shared/JSON.svelte b/js/json/shared/JSON.svelte
index 0db903364e..aceab74a6f 100644
--- a/js/json/shared/JSON.svelte
+++ b/js/json/shared/JSON.svelte
@@ -1,6 +1,5 @@
 <script lang="ts">
-	import { onDestroy } from "svelte";
-	import { fade } from "svelte/transition";
+	import { onDestroy, onMount } from "svelte";
 	import { JSON as JSONIcon } from "@gradio/icons";
 	import { Empty } from "@gradio/atoms";
 	import JSONNode from "./JSONNode.svelte";
@@ -10,6 +9,17 @@
 	export let open = false;
 	export let theme_mode: "system" | "light" | "dark" = "system";
 	export let show_indices = false;
+	export let lines: number | undefined;
+
+	let json_holder: HTMLDivElement;
+	let line_height: number;
+
+	onMount(() => {
+		if (json_holder) {
+			const computed_style = window.getComputedStyle(json_holder);
+			line_height = parseFloat(computed_style.lineHeight);
+		}
+	});
 
 	let copied = false;
 	let timer: NodeJS.Timeout;
@@ -41,6 +51,9 @@
 	onDestroy(() => {
 		if (timer) clearTimeout(timer);
 	});
+
+	$: max_height =
+		lines && line_height ? `${(lines + 1) * line_height}px` : "auto";
 </script>
 
 {#if value && value !== '""' && !is_empty(value)}
@@ -57,7 +70,11 @@
 			<Copy />
 		{/if}
 	</button>
-	<div class="json-holder">
+	<div
+		class="json-holder"
+		bind:this={json_holder}
+		style:max-height={max_height}
+	>
 		<JSONNode
 			{value}
 			depth={0}
diff --git a/js/json/shared/JSONNode.svelte b/js/json/shared/JSONNode.svelte
index 68fc1c6004..e1eabc9b82 100644
--- a/js/json/shared/JSONNode.svelte
+++ b/js/json/shared/JSONNode.svelte
@@ -51,6 +51,7 @@
 					"aria-roledescription",
 					`Line number ${index + 1}`
 				);
+				line_number?.setAttribute("title", `Line number ${index + 1}`);
 			}
 		});
 	}
@@ -200,7 +201,9 @@
 		color: var(--line-number-color);
 		user-select: none;
 		text-overflow: ellipsis;
-		padding-right: 4px;
+		text-overflow: ellipsis;
+		direction: rtl;
+		overflow: hidden;
 	}
 	.content {
 		flex: 1;
diff --git a/test/components/test_json.py b/test/components/test_json.py
index 67fc76f75e..9faa945bcc 100644
--- a/test/components/test_json.py
+++ b/test/components/test_json.py
@@ -23,6 +23,7 @@ def test_component_functions(self):
             "value": None,
             "show_label": True,
             "label": None,
+            "lines": None,
             "name": "json",
             "proxy_url": None,
             "_selectable": False,


Code review comments:
diff_hunk: @@ -67,6 +68,7 @@ def __init__(
             key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
             open: If True, all JSON nodes will be expanded when rendered. By default, node levels deeper than 3 are collapsed.
             show_indices: Whether to show numerical indices when displaying the elements of a list within the JSON object.
+            lines: Maximum number of visible lines to show in the component. Overflow will be scrollable.
path: gradio/components/json_component.py
text: @user1:
In light of the previous comment, I would suggest naming this parameter `max_lines` to be consistent with `gr.Textbox`

diff_hunk: @@ -122,6 +122,7 @@ def __init__(
             elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
             render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
             key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
+            lines: Maximum number of visible lines to show in the code editor. Overflow will be scrollable.
path: gradio/components/code.py
text: @user1:
Just tested and it looks like the `lines` parameter actually behaves differently than this. Its more like the `lines` parameter in `gr.Textbox`, which is the *minimum* number of visible lines to show. If the code takes up more than this number of lines, the full code will be shown. We *could* add a `max_lines` parameter, but that's a separate issues

@author:
Oh!