A page-level hero pattern featuring a headline, subtitle, call-to-action buttons, and a primary media element. Supports images, videos, or custom React elements with enforced aspect ratios and object-fit constraints.
The HeaderHeroPrimaryMedia component provides a structured hero section with:
- Responsive headline and subtitle layout
- Primary and optional secondary call-to-action buttons
- Media element (image, video, or custom) with responsive aspect ratios
- Development-time validation warnings
import HeaderHeroPrimaryMedia from "shared/sections/HeaderHeroPrimaryMedia/HeaderHeroPrimaryMedia";
function MyPage() {
return (
<HeaderHeroPrimaryMedia
headline="Build on XRPL"
subtitle="Start developing today with our comprehensive developer tools."
links={[{ label: "Get Started", href: "/docs" }]}
media={{
type: "image",
src: "/img/hero.png",
alt: "XRPL Development",
}}
/>
);
}| Prop | Type | Required | Description |
|---|---|---|---|
headline | React.ReactNode | Yes | Hero headline text (display-md typography) |
subtitle | React.ReactNode | Yes | Hero subtitle text (label-l typography) |
links | DesignConstrainedLink[] | No | Array of { label, href } for ButtonGroup |
media | HeaderHeroMedia | Yes | Media element (image, video, or custom) |
stacked | boolean | No | Stack headline, subtitle, and buttons in one column. Defaults to false. See Layout |
className | string | No | Additional CSS classes for the header element |
...rest | HTMLHeaderElement attributes | No | Any other HTML header attributes |
The links prop accepts an array of { label, href } objects for consistent ButtonGroup rendering; variant and color are set by the component:
- First link:
variant="primary",color="green" - Second link:
variant="tertiary",color="green" - Max 2 links supported (ButtonGroup validation)
stacked | Layout |
|---|---|
false (default) | Two columns: headline on the left (5 of 12 on lg), subtitle and buttons on the right. The headline bottom-aligns against the CTA column. |
true | One column (full width at base, 7 of 8 at md, 9 of 12 at lg — note this grid is 4/8/12 columns by breakpoint, not 12 throughout): headline, then subtitle, then buttons, with 16px between the headline and subtitle. The subtitle-to-buttons gap keeps the standard 24px (40px on lg). |
<HeaderHeroPrimaryMedia
stacked
headline="Build on the XRP Ledger"
subtitle="Everything you need to get started."
media={{ type: "image", src: "/hero.jpg", alt: "Hero" }}
/>Media placement is unchanged — it stays full-width below the text in both layouts.
The media prop accepts a discriminated union of three types:
media={{
type: "image",
src: string, // Required
alt: string, // Required
// ... all native <img> props except className and style
}}Example:
media={{
type: "image",
src: "/img/hero.png",
alt: "Hero image",
loading: "lazy",
decoding: "async"
}}media={{
type: "video",
src: string, // Required
alt?: string, // Optional but recommended
// ... all native <video> props except className and style
}}Example:
media={{
type: "video",
src: "/video/intro.mp4",
alt: "Introduction video",
autoPlay: true,
loop: true,
muted: true,
playsInline: true
}}media={{
type: "custom",
element: React.ReactElement // Required
}}Example:
media={{
type: "custom",
element: <MyAnimationComponent />
}}<HeaderHeroPrimaryMedia
headline="Real-world asset tokenization"
subtitle="Learn how to issue crypto tokens and build solutions."
links={[
{ label: "Get Started", href: "/docs" },
{ label: "Learn More", href: "/about" },
]}
media={{
type: "image",
src: "/img/tokenization.png",
alt: "Tokenization",
}}
/><HeaderHeroPrimaryMedia
headline="Watch and Learn"
subtitle="Explore our video tutorials."
links={[{ label: "Watch Tutorials", href: "/tutorials" }]}
media={{
type: "video",
src: "/video/intro.mp4",
alt: "Introduction video",
autoPlay: true,
loop: true,
muted: true,
}}
/><HeaderHeroPrimaryMedia
headline="Interactive Experience"
subtitle="Engage with custom media."
links={[{ label: "Explore", href: "/interactive" }]}
media={{
type: "custom",
element: <MyAnimationComponent />,
}}
/>The component enforces specific design requirements:
- Aspect Ratios: Media maintains responsive aspect ratios:
- Base:
16:9 - Medium (md+):
2:1 - Large (lg+):
3:1
- Base:
- Object Fit: All media uses
object-fit: coverto fill the container - Type Safety: TypeScript discriminated unions ensure type-safe media selection
The component includes development-time validation that logs warnings to the console when required props are missing:
- Missing
headline: Component returnsnull(error logged) - Missing
subtitle,links, ormedia: Warning logged, component still renders
The component generates the following CSS classes:
bds-header-hero-primary-media- Root header elementbds-header-hero-primary-media--stacked- Root modifier, present whenstackedis setbds-header-hero-primary-media__stack- Single-column wrapper, only rendered whenstackedis setbds-header-hero-primary-media__headline- Headline containerbds-header-hero-primary-media__subtitle- Subtitle elementbds-header-hero-primary-media__cta-container- CTA containerbds-header-hero-primary-media__cta-buttons- CTA buttons wrapperbds-header-hero-primary-media__media-container- Media containerbds-header-hero-primary-media__media-element- Media element
- Media Selection: Choose media that works well with the responsive aspect ratios (16:9 base, 2:1 md+, 3:1 lg+)
- Alt Text: Always provide meaningful alt text for images and videos
- Performance: Use
loading="lazy"for images below the fold - CTAs: Keep CTA text concise and action-oriented
- Headlines: Keep headlines concise and impactful