I have a Next.js application with a collapsible sidebar and a shared layout. When the sidebar expands or collapses, I want the main content of my pages to always remain horizontally centered within the remaining available width (viewport width minus sidebar width).
Current structure: A fixed sidebar that toggles between 16rem (expanded) and 4.5rem (collapsed) A navbar at the top Main content area that should be centered
Here's my shared layout component:
function LayoutContent({
children,
}: {
children: (props: { isCollapsed: boolean }) => React.ReactNode;
}) {
const { state } = useSidebar();
const isCollapsed = state === "collapsed";
return (
<div className="flex">
<Navbar />
<AppSidebar />
<div className="flex-1 pl-24 pt-24 md:pl-[100px] md:pt-[100px] transition-all duration-300">
{children({ isCollapsed })}
</div>
</div>
);
}
And here's how a page uses it:
<SharedLayout>
{({ isCollapsed }) => (
<div className={`mx-auto ${isCollapsed ? 'max-w-[calc(100vw-4.5rem)]' : 'max-w-[calc(100vw-16rem)]'}`}>
{/* Page content */}
</div>
)}
</SharedLayout>
The issues I'm facing is that the content doesn't stay perfectly centered during the sidebar transition. What's the best way to implement this so that the content remains centered regardless of sidebar state.
What you probably want to do is group the SideBar and the content (children) into one flexbox row. By doing this, flex will handle your resize and centering.
I'm going to assume that your SideBar
uses "position: fixed"
CSS property (docs) and that's causing you a lot of headache. This property allows SideBar
to stay at the same place at your screen regardless of your scrolling. But what it also does is omit the element from the layout computation, so your flex around this will not keep it size in mind while computing sizes for other elements.
I made a little demo that solves the issue you have:
https://codesandbox.io/p/devbox/4m3k5y
(click
change
button in the sidebar to see the resize behavior)
What the demo does is grouping the SideBar
and the page content into one div
with a flex (as mentioned above). But besides just doing that, it applies the position: fixed
CSS property to this grouping div
instead of SideBar
(SideBar
doesn't have the fixed
property anymore), allowing for automatic size change calculations.
🗒️ Moreover, the content side has the
overflow-y-scroll
Tailwind class name, which makes the content vertically scrollable if it overflows over the screen height.
Hopefully that's what you were looking for, if you have anymore questions, feel free to ask.