From a84106690dfa3b50db66d66269ebf08c41e703e0 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Tue, 13 Jan 2026 18:32:37 -0500 Subject: [PATCH 1/3] [bugfix] Support `Panel` `defaultSize={0}` (#600) --- CHANGELOG.md | 4 +++ .../tests/tests/default-sizes.spec.tsx | 26 ++++++++++++++----- lib/global/dom/calculatePanelConstraints.ts | 8 +++--- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3074ce259..27a586c25 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 4.4.1 + +- [600](https://github.com/bvaughn/react-resizable-panels/pull/600): Bugfix: Collapsible `Panel` should treat `defaultSize={0}` as _collapsed_ on mount + ## 4.4.0 - [599](https://github.com/bvaughn/react-resizable-panels/pull/599): Add new `onLayoutChanged` prop to `Group`. diff --git a/integrations/tests/tests/default-sizes.spec.tsx b/integrations/tests/tests/default-sizes.spec.tsx index 9a41a4733..998534f1f 100644 --- a/integrations/tests/tests/default-sizes.spec.tsx +++ b/integrations/tests/tests/default-sizes.spec.tsx @@ -12,14 +12,17 @@ test.describe("default panel sizes", () => { + + , { usePopUpWindow } ); await expect(page.getByText("id: left")).toContainText("30%"); - await expect(page.getByRole("separator")).toBeVisible(); + await expect(page.getByText("id: middle")).toContainText("0%"); await expect(page.getByText("id: right")).toContainText("70%"); + await expect(page.getByRole("separator")).toHaveCount(2); }); test("pixels", async ({ page: mainPage }) => { @@ -28,14 +31,17 @@ test.describe("default panel sizes", () => { + + , { usePopUpWindow } ); await expect(page.getByText("id: left")).toContainText("200px"); - await expect(page.getByRole("separator")).toBeVisible(); - await expect(page.getByText("id: right")).toContainText("776px"); + await expect(page.getByText("id: middle")).toContainText("0px"); + await expect(page.getByText("id: right")).toContainText("752px"); + await expect(page.getByRole("separator")).toHaveCount(2); }); test("rems", async ({ page: mainPage }) => { @@ -44,14 +50,17 @@ test.describe("default panel sizes", () => { + + , { usePopUpWindow } ); await expect(page.getByText("id: left")).toContainText("160px"); - await expect(page.getByRole("separator")).toBeVisible(); - await expect(page.getByText("id: right")).toContainText("816px"); + await expect(page.getByText("id: middle")).toContainText("0px"); + await expect(page.getByText("id: right")).toContainText("792px"); + await expect(page.getByRole("separator")).toHaveCount(2); }); test("vw", async ({ page: mainPage }) => { @@ -60,14 +69,17 @@ test.describe("default panel sizes", () => { + + , { usePopUpWindow } ); await expect(page.getByText("id: left")).toContainText("250px"); - await expect(page.getByRole("separator")).toBeVisible(); - await expect(page.getByText("id: right")).toContainText("726px"); + await expect(page.getByText("id: middle")).toContainText("0px"); + await expect(page.getByText("id: right")).toContainText("702px"); + await expect(page.getByRole("separator")).toHaveCount(2); }); }); } diff --git a/lib/global/dom/calculatePanelConstraints.ts b/lib/global/dom/calculatePanelConstraints.ts index 39327ae89..fa1e0b922 100644 --- a/lib/global/dom/calculatePanelConstraints.ts +++ b/lib/global/dom/calculatePanelConstraints.ts @@ -25,7 +25,7 @@ export function calculatePanelConstraints(group: RegisteredGroup) { const { element, panelConstraints } = panel; let collapsedSize = 0; - if (panelConstraints.collapsedSize) { + if (panelConstraints.collapsedSize !== undefined) { const pixels = sizeStyleToPixels({ groupSize, panelElement: element, @@ -36,7 +36,7 @@ export function calculatePanelConstraints(group: RegisteredGroup) { } let defaultSize: number | undefined = undefined; - if (panelConstraints.defaultSize) { + if (panelConstraints.defaultSize !== undefined) { const pixels = sizeStyleToPixels({ groupSize, panelElement: element, @@ -47,7 +47,7 @@ export function calculatePanelConstraints(group: RegisteredGroup) { } let minSize = 0; - if (panelConstraints.minSize) { + if (panelConstraints.minSize !== undefined) { const pixels = sizeStyleToPixels({ groupSize, panelElement: element, @@ -58,7 +58,7 @@ export function calculatePanelConstraints(group: RegisteredGroup) { } let maxSize = 100; - if (panelConstraints.maxSize) { + if (panelConstraints.maxSize !== undefined) { const pixels = sizeStyleToPixels({ groupSize, panelElement: element, From e08923e710e1d242771d65e0210fb9b42503d143 Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Tue, 13 Jan 2026 18:33:01 -0500 Subject: [PATCH 2/3] 4.4.0 -> 4.4.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7f73c4fd9..4406c7788 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-resizable-panels", - "version": "4.4.0", + "version": "4.4.1", "type": "module", "author": "Brian Vaughn (https://github.com/bvaughn/)", "contributors": [ From c448576deb72e9bbc1979474448c098319aa1a9f Mon Sep 17 00:00:00 2001 From: Brian Vaughn Date: Tue, 13 Jan 2026 18:53:01 -0500 Subject: [PATCH 3/3] Add collapsed-by-default example to docs --- .../CollapsiblePanelsCollapsedByDefault.json | 3 +++ src/routes/CollapsiblePanelsRoute.tsx | 20 +++++++++++++++++++ .../CollapsiblePanelsCollapsedByDefault.tsx | 10 ++++++++++ 3 files changed, 33 insertions(+) create mode 100644 public/generated/examples/CollapsiblePanelsCollapsedByDefault.json create mode 100644 src/routes/examples/CollapsiblePanelsCollapsedByDefault.tsx diff --git a/public/generated/examples/CollapsiblePanelsCollapsedByDefault.json b/public/generated/examples/CollapsiblePanelsCollapsedByDefault.json new file mode 100644 index 000000000..b39134e6c --- /dev/null +++ b/public/generated/examples/CollapsiblePanelsCollapsedByDefault.json @@ -0,0 +1,3 @@ +{ + "html": "
<Group>
\n
<Panel collapsible defaultSize=\"0%\" minSize=\"10%\" />
\n
<Separator />
\n
<Panel />
\n
</Group>
" +} \ No newline at end of file diff --git a/src/routes/CollapsiblePanelsRoute.tsx b/src/routes/CollapsiblePanelsRoute.tsx index c973ffb8b..ca3437aca 100644 --- a/src/routes/CollapsiblePanelsRoute.tsx +++ b/src/routes/CollapsiblePanelsRoute.tsx @@ -1,5 +1,6 @@ import { Box, Callout, Code, Header } from "react-lib-tools"; import { html as ExampleHTML } from "../../public/generated/examples/CollapsiblePanels.json"; +import { html as ExampleCollapsedByDefaultHTML } from "../../public/generated/examples/CollapsiblePanelsCollapsedByDefault.json"; import { html as ExampleWithCollapsedSizeHTML } from "../../public/generated/examples/CollapsiblePanelsCollapsedSize.json"; import { Group } from "../components/styled-panels/Group"; import { Panel } from "../components/styled-panels/Panel"; @@ -48,6 +49,25 @@ export default function CollapsiblePanelsRoute() { A panel's collapse threshold is half its minimum size. +
+ Collapsible panels can also be collapsed by default by setting their{" "} + defaultSize to 0 (pixels or percent). +
+ + + + + + The panel on the left is collapsed by default but can be expanded by + dragging the separator. + + ); } diff --git a/src/routes/examples/CollapsiblePanelsCollapsedByDefault.tsx b/src/routes/examples/CollapsiblePanelsCollapsedByDefault.tsx new file mode 100644 index 000000000..e22fa2baf --- /dev/null +++ b/src/routes/examples/CollapsiblePanelsCollapsedByDefault.tsx @@ -0,0 +1,10 @@ +import { Group, Panel, Separator } from "react-resizable-panels"; + +// + +/* prettier-ignore */ + + + + +