A dumb CSS Grid skeleton with sidebar, topbar, and content regions. It has no opinion on what the sidebar or topbar contain — the elements passed in are responsible for their own `grid-area: sidebar` / `grid-area: topbar` placement (e.g. via `@behivetech/atoms.sidebar`).

pnpm add @behivetech/templates.sidebar-layout

You are viewing Sidebar Layout v0.5.0, snapshotted 2026-11-09. The latest is v0.5.1. Go to the latest →

registry/behivetech/templates/sidebar-layout at v0.5.0, snapshotted 2026-11-09

sidebar-layout.tsx
1import { type HTMLAttributes, type ReactNode } from "react";
2import { getClassName } from "@bht-component-registry/class-names";
3import styles from "./sidebar-layout.module.scss";
4
5export interface SidebarLayoutProps extends HTMLAttributes<HTMLDivElement> {
6 /** Additional class names to merge with the component root element */
7 className?: string;
8 /** Sidebar region content; the element rendered here owns its own `grid-area: sidebar` placement */
9 sidebar: ReactNode;
10 /** Topbar region content; the element rendered here owns its own `grid-area: topbar` placement */
11 topbar: ReactNode;
12 /** Main content region */
13 children?: ReactNode;
14}
15
16/**
17 * Dumb CSS Grid skeleton with sidebar, topbar, and content regions.
18 * Composition of the actual sidebar/topbar/content is left entirely to the
19 * consumer — this only owns the grid tracks and the content scroll area.
20 */
21export const SidebarLayout = ({
22 className,
23 sidebar,
24 topbar,
25 children,
26 ...rest
27}: SidebarLayoutProps) => {
28 const [rootClass, getChildClass] = getClassName({
29 className,
30 rootClass: "BHT__SidebarLayout",
31 styles,
32 });
33
34 return (
35 <div {...rest} className={rootClass}>
36 {sidebar}
37 <div className={getChildClass("main")}>
38 {topbar}
39 <main className={getChildClass("content")}>
40 <div className={getChildClass("inner")}>{children}</div>
41 </main>
42 </div>
43 </div>
44 );
45};
sidebar-layout.module.scss
1.BHT__SidebarLayout {
2 display: grid;
3 grid-template-columns: var(--sidebar-layout-sidebar-width, 13.75rem) 1fr;
4 grid-template-rows: var(--sidebar-layout-topbar-height, 3.5rem) 1fr;
5 grid-template-areas:
6 "sidebar topbar"
7 "sidebar content";
8 min-height: 100vh;
9
10 &__main {
11 grid-column: 2;
12 display: contents;
13 }
14
15 &__content {
16 grid-area: content;
17 background: var(
18 --sidebar-layout-content-background,
19 var(--md-sys-color-background, var(--color-background))
20 );
21 color: var(--md-sys-color-on-background, var(--color-text-body));
22 overflow-y: auto;
23 }
24
25 &__inner {
26 padding: var(--sidebar-layout-content-padding, var(--spacing-8));
27 max-width: var(--sidebar-layout-content-max-width, 75rem);
28 }
29}
index.ts
1export { SidebarLayout } from "./sidebar-layout.js";
2export type { SidebarLayoutProps } from "./sidebar-layout.js";
sidebar-layout.example.tsx
1import { SidebarLayout } from "./sidebar-layout.js";
2
3export const BasicSidebarLayout = () => (
4 <SidebarLayout sidebar={<nav>Sidebar</nav>} topbar={<header>Topbar</header>}>
5 Page content
6 </SidebarLayout>
7);