Layout Components
Composing site layouts with Site, Header, Footer, and page components
Layout Components
Layout components provide the structural foundation for your site, composing together to create a complete page experience with consistent navigation, content areas, and footers.
Overview
The mdxui layout system follows a hierarchical composition pattern:
<Site> // Root wrapper
<Header /> // Navigation (automatic)
<LandingPage> // Main content area
{children} // Sections
</LandingPage>
<Footer /> // Footer (automatic)
</Site>Core Layout Components
Site Wrapper
The <Site> component is the root container that provides:
- Global theme context
- Automatic Header and Footer rendering
- Site metadata and configuration
- Layout shell for all pages
import { Site } from '@mdxui/beacon'
<Site name="Acme Inc" theme="system">
{/* Pages render here */}
</Site>See Site Component for full documentation.
Header Component
The <Header> component provides site navigation with:
- Logo and branding
- Navigation links
- Call-to-action buttons
- Responsive mobile menu
- Scroll effects
<Header
logo={<Logo />}
nav={[
{ label: "Features", href: "#features" },
{ label: "Pricing", href: "#pricing" },
{ label: "Docs", href: "/docs" },
]}
cta={{ label: "Get Started", href: "/signup" }}
/>See Header Component for full documentation.
Footer Component
The <Footer> component provides the site footer with:
- Logo and description
- Link groups organized in columns
- Social media links
- Copyright and status indicator
<Footer
logo={<Logo />}
companyName="Acme Inc"
linkGroups={[
{
group: "Product",
items: [
{ title: "Features", href: "/features" },
{ title: "Pricing", href: "/pricing" },
]
},
{
group: "Company",
items: [
{ title: "About", href: "/about" },
{ title: "Blog", href: "/blog" },
]
},
]}
socialLinks={[
{ name: "Twitter", href: "https://twitter.com/acme", icon: <Twitter /> },
{ name: "GitHub", href: "https://github.com/acme", icon: <GitHub /> },
]}
/>See Footer Component for full documentation.
Page Components
Page components define the main content area layout and sit within the Site wrapper.
LandingPage Component
Container for marketing landing pages with composable sections:
<LandingPage>
<Hero
title="Build Better Products"
subtitle="Ship faster with our platform"
cta={{ label: "Get Started", href: "/signup" }}
/>
<Features
title="Key Features"
features={features}
/>
<Pricing
title="Simple Pricing"
tiers={pricingTiers}
/>
<CTA
title="Ready to start?"
cta={{ label: "Sign Up", href: "/signup" }}
/>
</LandingPage>Features:
- Flexible section composition
- Semantic
<main>element - Responsive spacing
- Full-width section support
See LandingPage Component for full documentation.
Page Component
Simple layout for content pages like About, Contact, Privacy:
<Page title="About Us" description="Learn about our company">
<div className="prose lg:prose-xl">
<h2>Our Story</h2>
<p>Founded in 2020, we set out to...</p>
<h2>Our Team</h2>
<TeamGrid members={team} />
</div>
</Page>Features:
- Optional title and description
- Flexible content structure
- Works great with MDX
- Typography (prose) support
See Page Component for full documentation.
Layout Composition Patterns
Basic Marketing Site
Complete site with header, landing page sections, and footer:
<Site name="Acme Inc" theme="system">
<LandingPage>
<Hero
title="Welcome to Acme"
subtitle="The best product you'll ever use"
cta={{ label: "Get Started", href: "/signup" }}
/>
<LogoCloud
title="Trusted by industry leaders"
logos={customerLogos}
/>
<Features
title="Everything You Need"
features={features}
variant="grid"
columns={3}
/>
<Testimonials
testimonials={testimonials}
variant="carousel"
/>
<Pricing
title="Simple Pricing"
tiers={pricingTiers}
showToggle={true}
/>
<FAQ
title="Common Questions"
items={faqItems}
/>
<CTA
title="Ready to get started?"
cta={{ label: "Start Free Trial", href: "/signup" }}
/>
</LandingPage>
</Site>Multi-Page Site
Combining landing page with content pages:
<Site name="Acme Inc">
{/* Homepage */}
<LandingPage>
<Hero />
<Features />
<Pricing />
</LandingPage>
{/* Content pages */}
<Page path="/about" title="About Us">
<div className="prose">
{/* About content */}
</div>
</Page>
<Page path="/contact" title="Contact">
<ContactForm />
</Page>
<Page path="/privacy" title="Privacy Policy">
<div className="prose">
{/* Legal content */}
</div>
</Page>
</Site>Custom Layout Wrapper
Creating a reusable layout wrapper:
import { LandingLayout } from '@mdxui/beacon'
export function AcmeLayout({ children }) {
return (
<LandingLayout
logo={<Logo />}
headerLinks={[
{ label: "Features", href: "#features" },
{ label: "Pricing", href: "#pricing" },
{ label: "Docs", href: "/docs" },
]}
primaryCta="Sign Up"
onPrimaryCta={() => router.push('/signup')}
companyName="Acme Inc"
footerLinkGroups={footerLinks}
socialLinks={socialLinks}
>
{children}
</LandingLayout>
)
}
// Usage
<AcmeLayout>
<Hero />
<Features />
<Pricing />
</AcmeLayout>Nested Layouts
Composing layouts for different site sections:
// Main site layout
<Site name="Acme">
{/* Marketing pages use LandingPage */}
<LandingPage>
<Hero />
<Features />
</LandingPage>
{/* Documentation uses DocsPage */}
<DocsPage>
<DocsSidebar />
<DocsContent />
</DocsPage>
{/* Blog uses BlogPage */}
<BlogPage>
<BlogGrid posts={posts} />
</BlogPage>
</Site>Responsive Design Considerations
Mobile-First Approach
All layout components use mobile-first responsive design:
// Header navigation
<nav className="hidden md:flex gap-6">
{/* Desktop navigation */}
</nav>
<button className="md:hidden">
{/* Mobile menu toggle */}
</button>
// Section spacing
<section className="py-12 md:py-24 lg:py-32">
{/* Mobile: 3rem, Tablet: 6rem, Desktop: 8rem */}
</section>
// Footer grid
<div className="grid gap-6 md:grid-cols-3 lg:grid-cols-5">
{/* Responsive column layout */}
</div>Breakpoint Strategy
Standard breakpoints across layout components:
- Mobile:
< 768px- Single column, stacked layout - Tablet:
>= 768px(md:) - 2-3 columns, side navigation - Desktop:
>= 1024px(lg:) - Full layout, expanded spacing - Wide:
>= 1280px(xl:) - Max-width containers
Container Widths
Consistent max-width containers:
// Standard container (most sections)
<div className="container max-w-7xl">
{/* Max width: 80rem (1280px) */}
</div>
// Narrow container (content pages)
<div className="container max-w-4xl">
{/* Max width: 56rem (896px) */}
</div>
// Wide container (full-bleed sections)
<div className="container max-w-screen-2xl">
{/* Max width: 96rem (1536px) */}
</div>Responsive Spacing
Vertical rhythm that scales with viewport:
// Section padding
py-12 md:py-24 lg:py-32
// Mobile: 3rem, Tablet: 6rem, Desktop: 8rem
// Container padding
px-4 md:px-6 lg:px-8
// Mobile: 1rem, Tablet: 1.5rem, Desktop: 2rem
// Gap between elements
gap-6 md:gap-8 lg:gap-12
// Mobile: 1.5rem, Tablet: 2rem, Desktop: 3remMobile Menu
The Header component includes responsive mobile navigation:
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false)
// Disable body scroll when menu is open
useEffect(() => {
if (isMobileMenuOpen) {
document.body.style.overflow = 'hidden'
}
return () => {
document.body.style.overflow = ''
}
}, [isMobileMenuOpen])Mobile menu features:
- Slides in from top
- Backdrop blur
- Body scroll lock
- Auto-close on navigation
- Accessible keyboard controls
Responsive Typography
Text scales with viewport for better readability:
// Page titles
<h1 className="text-4xl md:text-5xl lg:text-6xl">
// Section headings
<h2 className="text-3xl md:text-4xl lg:text-5xl">
// Body text
<p className="text-base md:text-lg lg:text-xl">
// Description text
<p className="text-sm md:text-base text-muted-foreground">Touch Targets
Interactive elements meet minimum touch target sizes (44x44px):
// Mobile menu button
<button className="h-10 w-10 md:hidden">
<Menu className="h-6 w-6" />
</button>
// Navigation links
<a className="py-2 px-4 min-h-[44px] flex items-center">
{label}
</a>
// CTA buttons
<Button size="lg" className="h-12 px-8">
Get Started
</Button>Layout Architecture
Component Hierarchy
Site // Root wrapper
├── ThemeProvider // Theme context
├── Header // Navigation
│ ├── Logo
│ ├── Navigation
│ │ └── NavItem[]
│ ├── MobileMenu
│ └── CTA Button
├── main // Content area
│ └── LandingPage | Page | DocsPage | BlogPage
│ └── children (sections/content)
└── Footer // Site footer
├── Logo
├── Description
├── LinkGroups[]
├── SocialLinks[]
└── CopyrightState Management
Layout state is minimal and local:
// Header scroll state
const [isScrolled, setIsScrolled] = useState(false)
// Mobile menu state
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false)
// Theme state (via context)
const { theme, setTheme } = useTheme()Context Providers
Site context for global configuration:
import { useSite } from '@mdxui/beacon'
function MyComponent() {
const { name, domain, theme } = useSite()
return <div>Welcome to {name}</div>
}Accessibility
Layout components implement WCAG 2.1 Level AA standards:
Semantic HTML
<Site>
<header> {/* Header component */}
<nav> {/* Navigation menu */}
<a href="/"> {/* Links */}
</nav>
</header>
<main> {/* Main content */}
<article> {/* Page or LandingPage */}
</main>
<footer> {/* Footer component */}
</footer>
</Site>Skip Links
Support for skip navigation:
<a href="#main-content" className="sr-only focus:not-sr-only">
Skip to main content
</a>
<main id="main-content">
{/* Content */}
</main>ARIA Labels
Proper labeling for assistive technology:
<button
aria-label={isMobileMenuOpen ? 'Close menu' : 'Open menu'}
aria-expanded={isMobileMenuOpen}
>
<Menu />
</button>
<nav aria-label="Main navigation">
{/* Navigation links */}
</nav>
<nav aria-label="Footer navigation">
{/* Footer links */}
</nav>Keyboard Navigation
All interactive elements are keyboard accessible:
- Tab navigation through links and buttons
- Enter/Space to activate buttons
- Escape to close mobile menu
- Focus indicators on all interactive elements
Focus Management
// Visible focus indicators
<a className="focus:outline-none focus:ring-2 focus:ring-primary">
{label}
</a>
// Focus trap in mobile menu
<Dialog open={isMobileMenuOpen}>
{/* Focus trapped within menu */}
</Dialog>Performance
Layout Optimization
Layout components are optimized for performance:
Minimal Re-renders:
// Header state is isolated
const Header = memo(function Header({ logo, nav, cta }) {
// Only re-renders when props change
})Lazy Loading:
// Mobile menu only loads when needed
const MobileMenu = lazy(() => import('./MobileMenu'))
{isMobileMenuOpen && (
<Suspense fallback={null}>
<MobileMenu />
</Suspense>
)}CSS Transitions:
// Use CSS for animations (GPU accelerated)
<header className="
transition-all duration-200
data-[scrolled=true]:bg-background/75
data-[scrolled=true]:backdrop-blur
">Best Practices
- Keep layout state minimal - Only track essential UI state
- Use CSS for animations - Avoid JavaScript-based animations
- Lazy load heavy components - Mobile menu, modals, etc.
- Memoize child components - Prevent unnecessary re-renders
- Use semantic HTML - Better for SEO and accessibility
TypeScript
Layout component type definitions:
import type { ReactNode, ComponentType } from 'react'
import type { Component } from 'mdxui'
// Site wrapper
export interface SiteProps {
name: string
domain?: string
theme?: 'light' | 'dark' | 'system'
children: ReactNode
}
// Page layouts
export interface LandingPageProps {
children: ReactNode
}
export interface PageProps {
title?: string
description?: string
children: ReactNode
}
// Layout composition
export interface LandingLayoutProps {
children: ReactNode
logo: ReactNode
headerLinks: HeaderLink[]
primaryCta?: string
onPrimaryCta?: () => void
companyName: string
footerLinkGroups?: FooterLinkGroup[]
socialLinks?: SocialLink[]
}Related Components
- Site Component - Root wrapper component
- Header Component - Navigation header
- Footer Component - Site footer
- LandingPage Component - Landing page layout
- Page Component - Generic page layout
- DocsPage Component - Documentation layout