1 GitHub star = 1 new component.

Star the repo
Layoutlayoutgridholygraildashboardstructure

Holy Grail Grid

Holy grail layout implemented with modern CSS grid.

Live Preview

Holy Grail Grid

Usage

Copy and paste this code into your React component:

tsx
import { HolyGrailGrid } from 'react-component-kit-ui/layout';

<HolyGrailGrid><div slot="header">Header</div><div slot="left">Sidebar</div><div slot="main">Content</div><div slot="footer">Footer</div></HolyGrailGrid>

Manual Installation

If you are not using the npm package, create a new file and paste the following code: src/components/HolyGrailGrid.tsx + HolyGrailGrid.css:

HolyGrailGrid.tsx
'use client';

import type { CSSProperties, ReactNode } from 'react';
import './HolyGrailGrid.css';

/** class:list โ†’ className */
function cx(...args: unknown[]): string {
  const out: string[] = [];
  const walk = (v: unknown) => {
    if (!v) return;
    if (typeof v === 'string' || typeof v === 'number') out.push(String(v));
    else if (Array.isArray(v)) v.forEach(walk);
    else if (typeof v === 'object') for (const [k, on] of Object.entries(v as Record<string, unknown>)) if (on) out.push(k);
  };
  args.forEach(walk);
  return out.join(' ');
}

/** "a: b; --c: d" โ†’ style object */
function st(css: string | undefined): CSSProperties {
  const o: Record<string, string> = {};
  for (const decl of String(css ?? '').split(';')) {
    const i = decl.indexOf(':');
    if (i < 0) continue;
    const k = decl.slice(0, i).trim();
    if (k) o[k.startsWith('--') ? k : k.replace(/-([a-z])/g, (_, c) => c.toUpperCase())] = decl.slice(i + 1).trim();
  }
  return o as CSSProperties;
}

/**
 * HolyGrailGrid โ€” Production-grade CSS grid layout container with sticky header, dual sidebars, fluid content, and footer.
 * 
 * @param {string} leftWidth - Left sidebar width. Default is '240px'.
 * @param {string} rightWidth - Right sidebar width. Default is '220px'.
 * @param {string} gap - Spacing gap between grid regions. Default is '1.5rem'.
 * @param {string} className - Optional CSS class.
 */
export interface HolyGrailGridProps {
  leftWidth?: string;
  rightWidth?: string;
  gap?: string;
  className?: string;
  children?: ReactNode;
  header?: ReactNode;
  left?: ReactNode;
  right?: ReactNode;
  footer?: ReactNode;
}

export function HolyGrailGrid({
  leftWidth = '240px',
  rightWidth = '220px',
  gap = '1.5rem',
  className = '',
  children,
  header,
  left,
  right,
  footer
}: HolyGrailGridProps) {
  return (
    <>
      <div className="cq-holy-grail-grid-cq" data-rk-7590db="">
      <div className={cx(['holy-grail', className])} style={st(`--hg-left: ${leftWidth}; --hg-right: ${rightWidth}; --hg-gap: ${gap};`)} data-rk-7590db="">
        <header className="holy-grail__header" data-rk-7590db="">
          {header}
        </header>
      
        <div className="holy-grail__middle" data-rk-7590db="">
          <aside className="holy-grail__left" data-rk-7590db="">
            {left}
          </aside>
      
          <main className="holy-grail__main" data-rk-7590db="">
            {children}
          </main>
      
          <aside className="holy-grail__right" data-rk-7590db="">
            {right}
          </aside>
        </div>
      
        <footer className="holy-grail__footer" data-rk-7590db="">
          {footer}
        </footer>
      </div>
      </div>
    </>
  );
}

export default HolyGrailGrid;
HolyGrailGrid.css
/* HolyGrailGrid โ€” ported from astro-component-kit (layout/HolyGrailGrid.astro) */

.cq-holy-grail-grid-cq:where([data-rk-7590db]) { container-type: inline-size; }
.holy-grail:where([data-rk-7590db]) {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  width: 100%;
  color: var(--c-text-1, #ffffff);
  font-family: var(--font-sans, system-ui, sans-serif);
}

.holy-grail__header:where([data-rk-7590db]) {
  width: 100%;
  padding: var(--sp-4, 1rem) var(--sp-6, 1.5rem);
  background: rgba(10, 10, 14, 0.8);
  backdrop-filter: blur(16px);
  border-bottom: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.08);
}

.holy-grail__middle:where([data-rk-7590db]) {
  display: grid;
  grid-template-columns: var(--hg-left) 1fr var(--hg-right);
  gap: var(--hg-gap);
  flex: 1;
  max-width: 1440px;
  margin: 0 auto;
  width: 100%;
  padding: var(--sp-6, 1.5rem);
}

.holy-grail__left:where([data-rk-7590db]),
.holy-grail__right:where([data-rk-7590db]) {
  padding: var(--sp-4, 1rem);
  background: rgb(var(--ink-rgb, 255 255 255) / 0.02);
  border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.06);
  border-radius: var(--r-lg, 16px);
  height: fit-content;
  position: sticky;
  top: 2rem;
}

.holy-grail__main:where([data-rk-7590db]) {
  padding: var(--sp-6, 1.5rem);
  background: rgb(var(--ink-rgb, 255 255 255) / 0.015);
  border: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.06);
  border-radius: var(--r-lg, 16px);
  min-height: 400px;
}

.holy-grail__footer:where([data-rk-7590db]) {
  width: 100%;
  padding: var(--sp-6, 1.5rem);
  background: rgba(10, 10, 14, 0.9);
  border-top: 1px solid rgb(var(--ink-rgb, 255 255 255) / 0.08);
  margin-top: auto;
}

@container (max-width: 1024px) {
  .holy-grail__middle:where([data-rk-7590db]) {
    grid-template-columns: var(--hg-left) 1fr;
  }
  .holy-grail__right:where([data-rk-7590db]) {
    display: none;
  }
}

@container (max-width: 768px) {
  .holy-grail__middle:where([data-rk-7590db]) {
    grid-template-columns: 1fr;
  }
  .holy-grail__left:where([data-rk-7590db]) {
    position: static;
  }
}

Quick Info

Category
Layout
Filename
HolyGrailGrid.tsx
Dependencies
None โ€” pure React + CSS
Tags
layoutgridholygraildashboardstructure