Search code examples
cssnext.jstailwind-cssshadcnui

ShadCn UI ResizablePanelGroup expand in the available space without specifying a custom height


I am stuck in a middle of CSS issue with ResizablePanelGroup component. In my page layout I am trying to place a header and a ResizablePanelGroup with 4 panels. Page should have a100vh and within that I want to place other components. After placing Header my ResizablePanelGroup should expand the rest of the height available in the space without manually specifying a height. Only the Content I am putting in the ResizablePanel should be scrollable when they exceed the space available in the panel.

image

Above is the current status of the layout and red are should expand the rest of the height available.

import ChatNav from "@/components/chat/ChatNav";
import Header from "@/components/common/Header";
import { Toggle } from "@/components/ui/toggle";
import UtilContext from "@/context/UtilContext";
import type { Metadata } from "next";
import { useContext, createContext } from "react";

export const metadata: Metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <div className="h-screen bg-black">
      <div className="absolute  inset-4">
        <UtilContext>
          <Header />

          <div className="bg-red-500"> {children}</div>
        </UtilContext>
      </div>
    </div>
  );
}
"use client";
import Chat from "@/components/chat/Chat";
import {
  ResizableHandle,
  ResizablePanel,
  ResizablePanelGroup,
} from "@/components/ui/resizable";
import ChatNav from "@/components/chat/ChatNav";
import { useContext } from "react";
import { UtilPanelContext } from "@/context/UtilContext";
import LSide from "@/components/chat/LSide";

const page = () => {
  const { leftPanel } = useContext(UtilPanelContext);

  return (
    <div className="h-full">
      {/* sidbar */}
      <ResizablePanelGroup direction="horizontal">
        {/* side nav */}
        <ResizablePanel defaultSize={10} className="min-w-[80px] max-w-[80px]">
          <div className="h-full flex flex-col">
            <div className="flex-grow-1"> Nav</div>
          </div>
          {/* <ChatNav /> */}
        </ResizablePanel>
        <ResizableHandle />

        {/* history panel */}
        <ResizablePanel defaultSize={leftPanel ? 30 : 0}>
          <div>LSide</div>
          {/* <LSide /> */}
        </ResizablePanel>
        <ResizableHandle withHandle />

        {/* chat workspace */}
        <ResizablePanel defaultSize={50}>
          <div>Chat</div>
          {/* <Chat /> */}
        </ResizablePanel>
        <ResizableHandle withHandle />

        {/* side panel */}
        <ResizablePanel defaultSize={50}>
          <h1>Hellow </h1>
        </ResizablePanel>
      </ResizablePanelGroup>
    </div>
  );
};

export default page;

image

Kind of the expectation I want. ResizablePanelGroup expands in the green color space and inner panels have scrollable views when the available space exceeds


Solution

  • First, we should fill the free vertical space with ResizablePanelGroup. We can do this with a vertical flex layout in RootLayout (assuming UtilContext does not render any HTML):

    <div className="absolute  inset-4 flex flex-col">
      <UtilContext>
        <Header />
        
        <div className="bg-red-500 min-h-0 grow"> {children}</div>
    

    Full height fill

    Then, to make each ResizablePanel vertically scrollable, apply overflow-y: auto !important or overflow-y: scroll !important to them via !overflow-y-auto or !overflow-y-scroll respectively. auto means a scrollbar only appears when needed, whereas scroll means a scrollbar will always be present. We need the !important flag to override the inline overflow: hidden style that are added to the HTML elements.

    <ResizablePanel defaultSize={50} className="!overflow-y-auto">
    

    See this working in this StackBlitz project.