Published on

How to Make ShadCN UI ResizablePanelGroup Expand Dynamically

Authors
  • Name
    Ripal & Zalak
    Twitter

When working with the ShadCN UI ResizablePanelGroup component, one common challenge is making it dynamically expand to fill the available space without manually specifying a height. This guide will help you achieve a layout where the ResizablePanelGroup fills the remaining space after placing other components like headers or sidebars.

The Challenge

Imagine you have a layout with a header and a ResizablePanelGroup containing four panels. The goal is for the ResizablePanelGroup to expand dynamically within the remaining height of a 100vh viewport. Furthermore, each panel's content should be scrollable when it exceeds the allocated height.

Here’s how we can address this using Tailwind CSS and React.


Step 1: Dynamic Height Adjustment

To make the ResizablePanelGroup fill the remaining space, we’ll leverage a vertical flex layout. Assume the UtilContext in your code does not render any HTML. Update the RootLayout component as follows:

<div className="absolute inset-4 flex flex-col">
  <UtilContext>
    <Header />
    <div className="min-h-0 grow bg-red-500">{children}</div>
  </UtilContext>
</div>
  • Key Changes:
    • Add flex flex-col to create a vertical flexbox layout.
    • Use min-h-0 and grow for the child div containing ResizablePanelGroup. This allows it to expand and fill the remaining space dynamically.

Step 2: Scrollable Panels

To make the content inside each ResizablePanel scrollable, apply the overflow-y-auto or overflow-y-scroll classes. Since ResizablePanel applies an inline overflow: hidden style, you need to override it using the !important flag in Tailwind CSS.

<ResizablePanel defaultSize={50} className="!overflow-y-auto">
  <div>Your scrollable content here</div>
</ResizablePanel>
  • Use !overflow-y-auto for scrollbars that appear only when necessary.
  • Use !overflow-y-scroll for persistent scrollbars.

Full Code Implementation

Here’s how your updated page component might look:

'use client'
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@/components/ui/resizable'

const Page = () => {
  return (
    <div className="h-full">
      <ResizablePanelGroup direction="horizontal">
        <ResizablePanel defaultSize={10} className="min-w-[80px] max-w-[80px]">
          <div className="flex h-full flex-col">Nav</div>
        </ResizablePanel>
        <ResizableHandle />
        <ResizablePanel defaultSize={30} className="!overflow-y-auto">
          <div>Left Side</div>
        </ResizablePanel>
        <ResizableHandle />
        <ResizablePanel defaultSize={50} className="!overflow-y-auto">
          <div>Chat Workspace</div>
        </ResizablePanel>
        <ResizableHandle />
        <ResizablePanel defaultSize={50} className="!overflow-y-auto">
          <div>Right Side</div>
        </ResizablePanel>
      </ResizablePanelGroup>
    </div>
  )
}

export default Page

Expected Outcome

After implementing these changes:

  1. The ResizablePanelGroup will expand to fill the available space within the viewport.
  2. Each panel will support scrolling for content exceeding its height.

FAQs

Q: Why use min-h-0?
A: The min-h-0 class ensures that the flex item (in this case, the ResizablePanelGroup) can shrink below its content size when necessary.

Q: What’s the difference between overflow-y-auto and overflow-y-scroll?
A: overflow-y-auto adds scrollbars only when needed, while overflow-y-scroll keeps them always visible.