Overview
The Hero section (also known as a hero banner, jumbotron, or above-the-fold banner) is a prominent visual component typically placed at the top of a page to immediately communicate the page's primary message, value proposition, or call-to-action. It is the first thing a user sees and sets the visual tone for the entire experience.
Hero sections combine typography, imagery (or color/gradient backgrounds), and calls-to-action into a single high-impact composition. They are used across marketing pages, landing pages, product pages, blog headers, and application dashboards.
When to use a Hero:
- At the top of landing pages to communicate the core value proposition
- On product pages to showcase the primary product with imagery and a CTA
- On blog posts or articles as a visual header with the title and metadata
- On dashboards or app pages as a welcome/overview banner
- On error pages (404, 500) to provide a branded, friendly experience
When NOT to use a Hero:
- On data-dense pages where users need immediate access to content (dashboards with many widgets)
- When the page serves a utility purpose where a hero adds unnecessary scrolling
- Below the fold — heroes are designed for the top of the page
- When you don't have strong visual content or a clear message — a weak hero damages credibility
Use the Gradient Generator to create background gradients for your hero. Set type scales with the Font Scale Generator. Verify text-over-image contrast with the Contrast Checker.
Variants
Layout Variants
| Variant | Description | Best For |
|---|---|---|
| Centered | All content centered horizontally and vertically. Single column. | Simple landing pages, announcement pages, brand pages |
| Split | Content on one side, image/media on the other (50/50 or 60/40). | Product pages, SaaS landing pages, feature showcases |
| Full-image | Full-bleed background image with overlaid text. | Visual-heavy brands, photography, travel, lifestyle |
| Video background | Looping video behind text content. | Modern SaaS, creative agencies, event pages |
| Gradient | Gradient background (solid or mesh) with text overlay. | Tech products, apps, where photography isn't available |
| Minimal | Text-only, no background image, relying on typography and whitespace. | Content-focused sites, blogs, documentation |
| Illustrated | Custom illustration (SVG/animation) alongside or behind text. | Playful brands, fintech, developer tools |
| Card hero | Content contained within a card element on a subtle background. | Dashboard welcomes, nested hero sections |
Size Variants
| Size | Height | Viewport Coverage | Use Case |
|---|---|---|---|
| Full viewport | 100vh | Entire screen | Brand-focused landing pages, single-page sites |
| Large | 70–80vh | Majority of viewport | Product pages, marketing pages |
| Medium | 50vh or 400–500px | Half viewport | Blog headers, secondary pages |
| Small | 200–300px | Compact | Section headers, dashboard banners |
Background Treatment
| Treatment | Description | Tool |
|---|---|---|
| Solid color | Single brand color | Contrast Checker |
| Linear gradient | Two or more colors in a directional gradient | Gradient Generator |
| Radial/mesh gradient | Complex multi-point gradients for depth | Gradient Generator |
| Image with overlay | Photo with semi-transparent color overlay for text readability | Contrast Checker |
| Image with scrim | Gradient overlay (transparent to dark) from text area toward image | Contrast Checker |
| Pattern/texture | SVG pattern or subtle texture behind content | — |
Properties
Hero Properties
| Property | Type | Default | Description |
|---|---|---|---|
variant | 'centered' | 'split' | 'fullImage' | 'minimal' | 'gradient' | 'centered' | Layout variant |
size | 'sm' | 'md' | 'lg' | 'full' | 'lg' | Height preset |
height | string | — | Custom height (overrides size) |
minHeight | string | — | Minimum height |
backgroundImage | string | — | URL for background image |
backgroundColor | string | — | Background color or CSS gradient |
overlay | boolean | true | Applies a semi-transparent overlay for text readability |
overlayColor | string | 'rgba(0,0,0,0.4)' | Overlay color and opacity |
overlayGradient | string | — | CSS gradient used as overlay (e.g., scrim) |
title | ReactNode | — | Primary heading content |
subtitle | ReactNode | — | Secondary text or description |
actions | ReactNode | — | CTA buttons or action elements |
media | ReactNode | — | Image, video, or illustration for split layout |
mediaPosition | 'left' | 'right' | 'right' | Side of the media in split variant |
textAlign | 'left' | 'center' | 'right' | 'center' | Text alignment within the content area |
maxWidth | string | '720px' | Maximum width of the text content area |
verticalAlign | 'top' | 'center' | 'bottom' | 'center' | Vertical alignment of content within the hero |
breadcrumb | ReactNode | — | Breadcrumb navigation displayed above the title |
badge | ReactNode | — | Badge or label above the title (e.g., "New", "Beta") |
className | string | — | Custom CSS class |
CSS Custom Properties
| Custom Property | Description | Default |
|---|---|---|
--hero-height | Section height | 80vh |
--hero-min-height | Minimum height | 400px |
--hero-bg | Background color/gradient | transparent |
--hero-overlay | Overlay color | rgba(0,0,0,0.4) |
--hero-content-max-width | Content max-width | 720px |
--hero-padding-x | Horizontal padding | 24px |
--hero-padding-y | Vertical padding | 48px |
--hero-title-size | Title font size | clamp(2rem, 5vw, 4rem) |
--hero-subtitle-size | Subtitle font size | clamp(1rem, 2vw, 1.5rem) |
Token Mappings
Design Token Mappings
| Token | Role | Typical Value |
|---|---|---|
color.bg.brand | Brand-colored hero background | Brand primary |
color.bg.surface | Minimal hero background | #ffffff / #1a1a1a |
color.text.on-brand | Text color on brand background | #ffffff |
color.text.on-dark | Text on dark overlays | #ffffff |
color.text.primary | Text on light/minimal heroes | #111827 |
color.text.secondary | Subtitle text on light heroes | #6b7280 |
font.size.display-lg | Hero title (large variant) | clamp(2.5rem, 5vw, 4.5rem) |
font.size.display-md | Hero title (medium variant) | clamp(2rem, 4vw, 3rem) |
font.size.xl | Hero subtitle | clamp(1.125rem, 2vw, 1.5rem) |
font.weight.bold | Title font weight | 700 |
font.weight.normal | Subtitle font weight | 400 |
line-height.tight | Title line height | 1.1–1.2 |
line-height.relaxed | Subtitle line height | 1.5–1.6 |
space.6 | Gap between title and subtitle | 24px |
space.8 | Gap between subtitle and CTA | 32px |
space.12 – space.16 | Hero vertical padding | 48–64px |
radius.lg – radius.xl | Card hero border radius | 16–24px |
Configure your typography scale with the Font Scale Generator. Preview gradient backgrounds in the Gradient Generator. Verify text contrast with the Contrast Checker.
States
Hero States
Hero is primarily a static presentational component, but it has important viewport-driven and content-driven states:
| State | Trigger | Effect |
|---|---|---|
| Default | Page load | Full hero renders with background, text, and CTAs |
| Responsive mobile | Viewport < 768px | Split heroes stack vertically, font sizes reduce via clamp(), padding decreases |
| Background loading | Large background image loading | Show a solid-color fallback or gradient while the image loads |
| Background loaded | Image fully loaded | Cross-fade or instant swap to the background image |
| Video playing | Autoplay video background | Video loops silently; falls back to poster image if autoplay is blocked |
| Reduced motion | prefers-reduced-motion: reduce | Video backgrounds pause (show poster), animations are disabled, parallax is removed |
| High contrast | prefers-contrast: more | Overlay opacity increases, text borders/shadows added for clarity |
| Print media | Background images hidden, text displayed in print-friendly colors |
Responsive Typography
Hero typography should use fluid sizing with clamp() to scale smoothly between viewport sizes:
.hero__title {
font-size: clamp(2rem, 5vw, 4rem);
line-height: 1.1;
}
.hero__subtitle {
font-size: clamp(1rem, 2vw, 1.5rem);
line-height: 1.5;
}
This eliminates the need for breakpoint-specific font-size media queries. Configure your fluid type scale with the Font Scale Generator.
Background Image Loading
Always provide a background-color fallback that closely matches the dominant color of the hero image. This prevents a jarring white-to-image flash:
.hero {
background-color: #1a1a2e; /* dominant image color */
background-image: url('hero.webp');
background-size: cover;
background-position: center;
}
Accessibility
Accessibility Requirements
Hero sections present significant accessibility challenges due to their reliance on visual impact, background imagery, and often low contrast ratios between text and backgrounds.
WCAG Success Criteria:
- 1.4.3 Contrast (Minimum) (Level AA): All text in the hero must achieve at least 4.5:1 contrast for normal text and 3:1 for large text (≥ 18pt or 14pt bold) against its background. For text over images, this means testing against the worst-case area of the image where text appears — not just the average color. Use a semi-transparent overlay or scrim gradient to guarantee contrast. Verify with the Contrast Checker.
- 1.4.6 Contrast (Enhanced) (Level AAA): For enhanced accessibility, aim for 7:1 (normal text) and 4.5:1 (large text). Hero titles (typically ≥ 24px bold) qualify as large text and need 3:1 minimum, 4.5:1 enhanced.
- 1.4.11 Non-text Contrast (Level AA): CTA buttons and interactive elements within the hero must maintain 3:1 contrast against their background.
- 1.1.1 Non-text Content (Level A): Background images that convey information (not purely decorative) must have text alternatives. If the background image is decorative (which is typical for heroes), it should be applied via CSS
background-image(which is inherently hidden from AT) rather than<img>. - 1.4.10 Reflow (Level AA): Hero content must reflow to a single column at 320px width without horizontal scrolling. Split heroes must stack. Full-viewport heroes should transition to auto-height on mobile.
- 2.3.1 Three Flashes or Below Threshold (Level A): Video backgrounds must not contain sequences that flash more than three times per second. This can trigger seizures. Review video content or use a static poster image fallback.
- 1.4.12 Text Spacing (Level AA): Hero text must remain readable when users apply custom text spacing (line-height 1.5×, letter-spacing 0.12em, word-spacing 0.16em, paragraph spacing 2×). Avoid fixed-height containers that clip text when spacing increases.
- 2.2.2 Pause, Stop, Hide (Level A): If the hero has an auto-playing video or animated content, provide controls to pause or stop it. For
prefers-reduced-motion: reduce, pause animations automatically.
Text-over-Image Strategies:
| Strategy | Contrast Guarantee | Performance |
|---|---|---|
Solid overlay (rgba(0,0,0,0.5)) | Strong, uniform | Simple, reliable |
| Gradient scrim (transparent → dark) | Strong in text area, image visible elsewhere | More visually sophisticated |
Text shadow (0 2px 4px rgba(0,0,0,0.8)) | Moderate, depends on image | Lightweight but less reliable |
| Background on text (semi-transparent pill) | Strong, localized | Can look dated |
| Dark image selection (curate only dark images) | Unreliable, varies by image | Fragile — avoid |
The recommended approach is a gradient scrim: a CSS gradient overlay that transitions from near-opaque behind the text to transparent toward the image focal point. This provides reliable contrast while preserving image visibility.
Usage Guidelines
Usage Guidelines
Do:
- Use fluid typography with
clamp()for responsive hero titles — configure with the Font Scale Generator - Always provide a
background-colorfallback that approximates the hero image's dominant color - Test text contrast against the worst-case background area, not the average — use the Contrast Checker
- Use a scrim gradient overlay for text-over-image heroes to ensure consistent contrast
- Keep hero messaging concise: one headline, one supporting line, one primary CTA
- Provide
prefers-reduced-motionhandling for video/animated heroes - Use
loading="eager"andfetchpriority="high"for hero images — they are the LCP element - Include a single clear call-to-action. If you must have two, make one primary and one secondary (ghost/outline)
Don't:
- Place critical content below a full-viewport hero on mobile — users may not realize they can scroll
- Use auto-playing video with sound — always mute autoplay videos
- Use text directly over busy images without an overlay — this virtually guarantees contrast failures
- Create heroes taller than the viewport on mobile — content below becomes invisible
- Use hero carousels/sliders — they have poor engagement rates and significant accessibility issues (see Carousel)
- Rely on background images for conveying essential information — they're invisible to screen readers and may not load
Performance Considerations:
| Optimization | Impact |
|---|---|
Use <img> with srcset/sizes for responsive image loading | Serves appropriately sized images per viewport |
| Use WebP/AVIF formats with JPEG fallback | 25–50% smaller file sizes |
Add fetchpriority="high" to the hero image | Browser prioritizes LCP image download |
| Inline critical CSS for the hero | Prevents FOUC (flash of unstyled content) |
Use aspect-ratio to prevent layout shift | Reserves space before image loads (CLS improvement) |
Hero Copy Hierarchy:
| Element | Character Limit | Typography |
|---|---|---|
| Badge/label | 15–20 chars | Small caps or tag style |
| Headline | 40–60 chars | Display font, bold |
| Subheadline | 80–150 chars | Body font, regular weight |
| Primary CTA | 15–25 chars | Button, primary variant |
| Secondary CTA | 15–25 chars | Button, ghost/outline variant |
Code Snippets
<!-- Centered hero with gradient background -->
<section class="hero hero--centered" style="
display: flex;
align-items: center;
justify-content: center;
min-height: 80vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #ffffff;
padding: 48px 24px;
text-align: center;
">
<div class="hero__content" style="max-width: 720px;">
<span class="hero__badge" style="
display: inline-block;
padding: 4px 12px;
background: rgba(255,255,255,0.2);
border-radius: 9999px;
font-size: 0.875rem;
margin-bottom: 16px;
">Now in Beta</span>
<h1 class="hero__title" style="
font-size: clamp(2rem, 5vw, 4rem);
line-height: 1.1;
margin: 0 0 16px;
font-weight: 700;
">Build beautiful interfaces faster</h1>
<p class="hero__subtitle" style="
font-size: clamp(1rem, 2vw, 1.5rem);
line-height: 1.5;
margin: 0 0 32px;
opacity: 0.9;
">A complete design system with accessible components, design tokens, and interactive tools.</p>
<div class="hero__actions" style="display: flex; gap: 12px; justify-content: center; flex-wrap: wrap;">
<a href="/get-started" class="btn btn--primary btn--lg">Get Started</a>
<a href="/docs" class="btn btn--ghost btn--lg" style="color: #fff; border: 1px solid rgba(255,255,255,0.3);">Documentation</a>
</div>
</div>
</section>
<!-- Split hero with image -->
<section class="hero hero--split" style="
display: grid;
grid-template-columns: 1fr 1fr;
min-height: 70vh;
align-items: center;
">
<div class="hero__content" style="padding: 48px;">
<h1 style="font-size: clamp(2rem, 4vw, 3.5rem); line-height: 1.1; margin: 0 0 16px;">
Your product headline
</h1>
<p style="font-size: 1.25rem; color: #6b7280; margin: 0 0 32px; line-height: 1.5;">
A compelling description of what your product does and why users should care.
</p>
<div style="display: flex; gap: 12px;">
<a href="/signup" class="btn btn--primary btn--lg">Start Free Trial</a>
</div>
</div>
<div class="hero__media">
<img src="hero-image.webp" alt="" loading="eager" fetchpriority="high"
style="width: 100%; height: 100%; object-fit: cover;" />
</div>
</section>
<style>
@media (max-width: 768px) {
.hero--split {
grid-template-columns: 1fr !important;
}
.hero--split .hero__content { order: 1; }
.hero--split .hero__media { order: 0; max-height: 300px; overflow: hidden; }
}
</style>import React from 'react';
interface HeroProps {
variant?: 'centered' | 'split' | 'fullImage' | 'minimal' | 'gradient';
size?: 'sm' | 'md' | 'lg' | 'full';
backgroundImage?: string;
backgroundColor?: string;
overlay?: boolean;
overlayColor?: string;
title: React.ReactNode;
subtitle?: React.ReactNode;
actions?: React.ReactNode;
media?: React.ReactNode;
mediaPosition?: 'left' | 'right';
badge?: React.ReactNode;
textAlign?: 'left' | 'center' | 'right';
maxWidth?: string;
className?: string;
}
const sizeMap = { sm: '300px', md: '50vh', lg: '80vh', full: '100vh' };
function Hero({
variant = 'centered',
size = 'lg',
backgroundImage,
backgroundColor = 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
overlay = true,
overlayColor = 'rgba(0,0,0,0.4)',
title,
subtitle,
actions,
media,
mediaPosition = 'right',
badge,
textAlign = variant === 'split' ? 'left' : 'center',
maxWidth = '720px',
className,
}: HeroProps) {
if (variant === 'split') {
return (
<section
className={className}
style={{
display: 'grid',
gridTemplateColumns: mediaPosition === 'right' ? '1fr 1fr' : '1fr 1fr',
minHeight: sizeMap[size],
alignItems: 'center',
}}
>
<div style={{ padding: 48, order: mediaPosition === 'left' ? 1 : 0 }}>
{badge && <div style={{ marginBottom: 16 }}>{badge}</div>}
<h1 style={{ fontSize: 'clamp(2rem, 4vw, 3.5rem)', lineHeight: 1.1, margin: '0 0 16px' }}>
{title}
</h1>
{subtitle && (
<p style={{ fontSize: '1.25rem', color: '#6b7280', margin: '0 0 32px', lineHeight: 1.5 }}>
{subtitle}
</p>
)}
{actions && <div style={{ display: 'flex', gap: 12, flexWrap: 'wrap' }}>{actions}</div>}
</div>
<div style={{ order: mediaPosition === 'left' ? 0 : 1, overflow: 'hidden', height: '100%' }}>
{media}
</div>
</section>
);
}
return (
<section
className={className}
style={{
position: 'relative',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
minHeight: sizeMap[size],
background: backgroundImage ? undefined : backgroundColor,
backgroundImage: backgroundImage ? `url(${backgroundImage})` : undefined,
backgroundSize: 'cover',
backgroundPosition: 'center',
color: '#ffffff',
padding: '48px 24px',
textAlign,
}}
>
{overlay && backgroundImage && (
<div
aria-hidden="true"
style={{
position: 'absolute',
inset: 0,
background: overlayColor,
}}
/>
)}
<div style={{ position: 'relative', maxWidth, zIndex: 1 }}>
{badge && <div style={{ marginBottom: 16 }}>{badge}</div>}
<h1 style={{ fontSize: 'clamp(2rem, 5vw, 4rem)', lineHeight: 1.1, margin: '0 0 16px', fontWeight: 700 }}>
{title}
</h1>
{subtitle && (
<p style={{ fontSize: 'clamp(1rem, 2vw, 1.5rem)', lineHeight: 1.5, margin: '0 0 32px', opacity: 0.9 }}>
{subtitle}
</p>
)}
{actions && (
<div style={{ display: 'flex', gap: 12, justifyContent: textAlign === 'center' ? 'center' : 'flex-start', flexWrap: 'wrap' }}>
{actions}
</div>
)}
</div>
</section>
);
}
// Usage
function LandingPage() {
return (
<Hero
variant="centered"
size="lg"
backgroundColor="linear-gradient(135deg, #667eea 0%, #764ba2 100%)"
badge={<span className="badge badge--outline">Now in Beta</span>}
title="Build beautiful interfaces faster"
subtitle="A complete design system with accessible components, design tokens, and interactive tools."
actions={
<>
<a href="/start" className="btn btn--primary btn--lg">Get Started</a>
<a href="/docs" className="btn btn--ghost btn--lg">Documentation</a>
</>
}
/>
);
}Design Systems
Design System Implementations
Hero sections are typically application-level compositions rather than standardized design system primitives. Most design systems provide the building blocks (typography, spacing, buttons, layout) and leave hero composition to the application layer. However, some systems include hero-specific components:
Bootstrap provides the Jumbotron (deprecated in v5) which was a simple padded container with a larger heading. In Bootstrap 5, the recommended approach is composing a hero from utility classes: py-5 text-center bg-body-tertiary with responsive grid columns. Bootstrap's Examples page includes several hero templates (centered, split, image background) as copy-paste starting points.
Material Design 3 does not include a "Hero" component. MUI's approach is to compose heroes from <Box>, <Container>, <Typography>, <Stack>, and <Button>. The Material Design spec does not define a hero section pattern, as it is more of a marketing/editorial pattern than an application UI pattern.
Chakra UI does not provide a Hero component. Chakra's documentation includes hero examples built from <Container>, <Heading>, <Text>, <Stack>, and <Button>. The philosophy is that heroes are too variable in layout and content to standardize into a single component.
Tailwind UI (the commercial component library for Tailwind CSS) provides numerous hero section templates in their "Marketing > Hero Sections" category. These include: simple centered, split with image, split with screenshot, angled background, with app screenshot, with phone mockup, and dark variants. Tailwind UI represents the most comprehensive hero pattern library available, though it is template-based rather than component-based.
Ant Design does not provide a hero component. Landing page patterns are available in Ant Design Pro and Ant Design Landing (a separate page builder tool) which includes hero section templates with animated text and scroll-triggered effects.
Shadcn/ui does not include a hero component but provides all building blocks. Community-contributed hero patterns are available through the Shadcn registry and typically combine the Card, Button, and typography primitives with Tailwind utilities.
The consensus across design systems is that heroes are composed, not componentized. The building blocks that matter most for heroes are: Stack for content layout, Grid for split layouts, typography components for display headings, and Button for CTAs.