mdxui

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.

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: 3rem

Mobile 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[]
    └── Copyright

State 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>

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

  1. Keep layout state minimal - Only track essential UI state
  2. Use CSS for animations - Avoid JavaScript-based animations
  3. Lazy load heavy components - Mobile menu, modals, etc.
  4. Memoize child components - Prevent unnecessary re-renders
  5. 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[]
}

On this page