mdxui

Hero Section

Above-the-fold hero section with headline, CTA, and visual content

Hero Section

The <Hero> section is the above-the-fold component that captures visitor attention with a compelling value proposition, primary call-to-action, and visual content. It's the first section users see and is critical for conversions.

Interface

import type { HeroProps } from 'mdxui'

interface HeroProps {
  /** Main headline */
  title: string
  /** Supporting subtitle or description */
  subtitle?: string
  /** Primary call-to-action */
  cta: CTA
  /** Secondary call-to-action */
  secondaryCta?: CTA
  /** Hero image URL */
  image?: string
  /** Hero video URL */
  video?: string
  /** Layout variant */
  variant?: 'default' | 'centered' | 'split'
}

interface CTA {
  text: string
  href: string
}

Usage

Basic Example

import { Hero } from '@mdxui/beacon'

<Hero
  title="Build faster with mdxui"
  subtitle="Type-safe React components for marketing sites, docs, and SaaS apps"
  cta={{ text: "Get Started", href: "/docs" }}
/>

With Secondary CTA

<Hero
  title="Ship your SaaS in days, not months"
  subtitle="Pre-built components for auth, billing, admin, and more"
  cta={{ text: "Start Free Trial", href: "/signup" }}
  secondaryCta={{ text: "View Demo", href: "/demo" }}
/>

With Image

<Hero
  title="Marketing sites that convert"
  subtitle="Landing pages, pricing, testimonials - all type-safe and ready to deploy"
  cta={{ text: "Browse Components", href: "/docs/site" }}
  image="/hero-dashboard.png"
  variant="split"
/>

With Video Background

<Hero
  title="Experience the difference"
  subtitle="See how teams are building faster with mdxui"
  cta={{ text: "Watch Demo", href: "#demo" }}
  video="/hero-background.mp4"
  variant="centered"
/>

Props

title (required)

Type: string

Main headline displayed prominently at the top of the hero section. Should be concise and communicate your core value proposition.

// Short and punchy
<Hero title="Ship faster" />

// Value-focused
<Hero title="Turn visitors into customers" />

// Product-focused
<Hero title="The all-in-one SaaS starter kit" />

subtitle (optional)

Type: string

Supporting text that elaborates on the headline. Provides additional context or benefits.

<Hero
  title="Build modern web apps"
  subtitle="Type-safe components that auto-wire to your backend"
/>

cta (required)

Type: CTA

Primary call-to-action button. This is your main conversion goal.

interface CTA {
  text: string    // Button text
  href: string    // Destination URL
}

<Hero
  title="Get started today"
  cta={{ text: "Start Free Trial", href: "/signup" }}
/>

secondaryCta (optional)

Type: CTA

Secondary call-to-action for users who aren't ready to commit. Often "Learn More" or "View Demo".

<Hero
  title="Transform your workflow"
  cta={{ text: "Get Started", href: "/signup" }}
  secondaryCta={{ text: "Watch Video", href: "#demo" }}
/>

image (optional)

Type: string

URL to hero image. Typically a product screenshot, dashboard view, or lifestyle image.

<Hero
  title="Beautiful dashboards"
  image="/dashboard-preview.png"
  variant="split"
/>

Best practices:

  • Use high-quality images (2x resolution for retina displays)
  • Optimize file size (WebP format recommended)
  • Recommended dimensions: 1200x800 or larger
  • Ensure image works on mobile (responsive)

video (optional)

Type: string

URL to background video. Adds motion and engagement to the hero.

<Hero
  title="See it in action"
  video="/hero-demo.mp4"
  variant="centered"
/>

Best practices:

  • Keep videos short (10-20 seconds)
  • Use small file sizes (< 5MB)
  • Mute by default
  • Provide fallback image
  • Test on mobile devices

variant (optional)

Type: 'default' | 'centered' | 'split' Default: 'default'

Controls the hero layout style.

// Default: Text left, image right
<Hero variant="default" />

// Centered: All content centered, no side image
<Hero variant="centered" />

// Split: 50/50 text and image columns
<Hero variant="split" />

Variant comparison:

  • default: Traditional asymmetric layout, text-heavy left side
  • centered: Simple, clean, works without images
  • split: Balanced layout showcasing visual content

Variants in Detail

Default Variant

Traditional marketing hero with text on the left, visual content on the right.

<Hero
  variant="default"
  title="Launch your startup faster"
  subtitle="Everything you need to go from idea to revenue"
  cta={{ text: "Start Building", href: "/signup" }}
  image="/product.png"
/>

Best for:

  • Product-focused landing pages
  • SaaS platforms
  • When you have strong visual content

Centered Variant

Minimal hero with centered content. Works great without images.

<Hero
  variant="centered"
  title="Documentation that developers love"
  subtitle="Fast, searchable, and always up to date"
  cta={{ text: "Get Started", href: "/docs" }}
  secondaryCta={{ text: "View Example", href: "/demo" }}
/>

Best for:

  • Documentation sites
  • Simple landing pages
  • Text-focused messaging

Split Variant

Balanced 50/50 layout with equal emphasis on text and visuals.

<Hero
  variant="split"
  title="Design meets functionality"
  subtitle="Beautiful components that just work"
  cta={{ text: "Explore Components", href: "/components" }}
  image="/design-system.png"
/>

Best for:

  • Design-focused products
  • Visual-heavy marketing
  • Showcasing UI/UX

Implementation Details

The reference implementation from @mdxui/beacon includes:

Features

  • Responsive Layout - Adapts from desktop to mobile
  • Gradient Backgrounds - Subtle gradient overlays
  • Smooth Animations - Fade-in effects on load
  • Optimized Images - Lazy loading and responsive srcsets
  • Video Support - Background videos with fallbacks
  • Accessibility - Semantic HTML and ARIA labels

Structure

<section className="hero">
  <div className="container">
    <div className="grid">
      {/* Text Content */}
      <div className="hero-content">
        <h1>{title}</h1>
        {subtitle && <p className="subtitle">{subtitle}</p>}

        <div className="cta-group">
          <Button href={cta.href}>{cta.text}</Button>
          {secondaryCta && (
            <Button variant="outline" href={secondaryCta.href}>
              {secondaryCta.text}
            </Button>
          )}
        </div>
      </div>

      {/* Visual Content */}
      {(image || video) && (
        <div className="hero-visual">
          {video ? (
            <video autoPlay muted loop playsInline>
              <source src={video} type="video/mp4" />
            </video>
          ) : (
            <img src={image} alt="" />
          )}
        </div>
      )}
    </div>
  </div>
</section>

Real-World Examples

SaaS Product Hero

<Hero
  title="Customer support that scales with you"
  subtitle="Help customers faster with AI-powered responses, live chat, and knowledge base"
  cta={{ text: "Start Free Trial", href: "/signup" }}
  secondaryCta={{ text: "Book Demo", href: "/demo" }}
  image="/support-dashboard.png"
  variant="split"
/>

Developer Tool Hero

<Hero
  variant="centered"
  title="Deploy in seconds, not hours"
  subtitle="Push to GitHub and watch your app go live. No configuration, no containers, no complexity."
  cta={{ text: "Get Started Free", href: "/signup" }}
  secondaryCta={{ text: "View Docs", href: "/docs" }}
/>

Agency Hero

<Hero
  title="We build digital products that matter"
  subtitle="From concept to launch, we partner with startups and enterprises to create exceptional web experiences"
  cta={{ text: "Start a Project", href: "/contact" }}
  secondaryCta={{ text: "View Our Work", href: "/portfolio" }}
  image="/agency-work.jpg"
  variant="default"
/>

E-commerce Hero

<Hero
  title="Premium coffee, delivered fresh"
  subtitle="Single-origin beans roasted weekly and shipped to your door"
  cta={{ text: "Shop Now", href: "/products" }}
  image="/coffee-hero.jpg"
  video="/coffee-process.mp4"
  variant="split"
/>

Accessibility

The reference implementation includes:

  • Semantic HTML - Uses <section>, <h1>, and <button> elements
  • Alt Text - Decorative images use empty alt attributes
  • Focus Indicators - Visible focus states on CTAs
  • Color Contrast - WCAG AA compliant text contrast
  • Keyboard Navigation - All CTAs are keyboard accessible
<section className="hero" aria-labelledby="hero-title">
  <h1 id="hero-title">{title}</h1>
  <p className="subtitle">{subtitle}</p>

  {/* Decorative image - empty alt */}
  {image && <img src={image} alt="" role="presentation" />}

  {/* Video with accessibility */}
  {video && (
    <video aria-label="Product demonstration" muted autoPlay loop>
      <source src={video} type="video/mp4" />
    </video>
  )}
</section>

Composition with LandingPage

The <Hero> is typically the first section in a <LandingPage>:

import { LandingPage, Hero, Features, CTA } from '@mdxui/beacon'

<LandingPage>
  <Hero
    title="Build amazing products"
    cta={{ text: "Get Started", href: "/signup" }}
  />
  <Features {...featuresProps} />
  <CTA {...ctaProps} />
</LandingPage>

Best Practices

Headlines

  • Keep it short: 5-10 words maximum
  • Lead with benefits: Focus on what users gain
  • Avoid jargon: Use clear, simple language
  • Test variations: A/B test different headlines

CTAs

  • Use action verbs: "Start", "Get", "Try", "Build"
  • Create urgency: "Start Free Trial" vs "Sign Up"
  • Be specific: "Get Started" vs "Click Here"
  • Limit choices: 1-2 CTAs maximum

Visuals

  • Show the product: Screenshots > stock photos
  • Use real data: Actual dashboards > mockups
  • Optimize loading: Lazy load, use WebP format
  • Test on mobile: Ensure images work on small screens

Performance

Image Optimization

// Use responsive images
<Hero
  image="/hero-large.webp"
  // Implementation handles responsive srcset:
  // srcset="/hero-small.webp 640w, /hero-medium.webp 1024w, /hero-large.webp 1920w"
/>

Lazy Loading

The reference implementation lazy-loads images that are below the fold:

<img
  src={image}
  loading="lazy"
  decoding="async"
  alt=""
/>

Video Best Practices

// Keep videos small and optimized
<video
  autoPlay
  muted
  loop
  playsInline
  poster="/video-poster.jpg"  // Fallback image
>
  <source src="/hero.mp4" type="video/mp4" />
</video>

TypeScript

Full type definitions:

import { z } from 'zod'
import type { Component } from 'mdxui'
import { CTASchema } from 'mdxui/zod'

export const HeroPropsSchema = z.object({
  title: z.string(),
  subtitle: z.string().optional(),
  cta: CTASchema,
  secondaryCta: CTASchema.optional(),
  image: z.string().optional(),
  video: z.string().optional(),
  variant: z.enum(['default', 'centered', 'split']).default('default'),
})

export type HeroProps = z.infer<typeof HeroPropsSchema>
export type Hero = Component<HeroProps>

On this page