Skip to content
ilinxa/pro-ui

Page Hero

alphav0.2.0

Full-bleed gradient hero band — badge, title, highlight, description, stats row, and a reveal-on-mount animation.

Category: MarketingUpdated: 2026-08-11Created: 2026-05-02Author: ilinxa

Context

Top-of-page hero band for landing pages, blog indexes, marketing sections, and app welcomes. Three density levels (compact / default / full) cover full-screen splashes down to sub-page banners. Engine is generic; news-flavored defaults live in dummy-data + demo (kasder NewsHero's content). Composable `children` slot supports stats / CTAs / search / anything. Migration origin: kasder kas-social-front-v0 commons/PageHero.tsx (engine) + sections/news/NewsHero.tsx (news-flavored shell). Drops framer-motion in favor of the existing pro-ui CSS keyframe — saves ~100KB peer dep + inherits prefers-reduced-motion respect for free.

Installation

Initialize shadcn (once per project)Seeds lib/utils.ts and components.json. Skip if you've already used any shadcn component.
pnpm dlx shadcn@latest init
Install the component
pnpm dlx shadcn@latest add @ilinxa/page-hero

Add -fixtures for dummy data:

pnpm dlx shadcn@latest add @ilinxa/page-hero-fixtures

CLI can't resolve @ilinxa? The namespace is listed in the official shadcn registry directory, so current CLIs need no configuration. If yours can't resolve it (older or pinned versions, self-hosted mirrors), register it manually in components.json:

"registries": {
  "@ilinxa": "https://ui.ilinxa.com/r/{name}.json"
}

Preview

News & Updates

Latest StoriesFrom Our Team

Insights, announcements, and behind-the-scenes from our editorial team.

Demo source

demo.tsxtsx
"use client"; import { Tabs, TabsContent, TabsTrigger } from "@/components/ui/tabs";import { SwipeTabsList } from "@/components/site/swipe-tabs-list";import { Button } from "@/components/ui/button";import { HeroStats, PageHero } from "./page-hero";import {  NEWS_HERO_DEFAULTS,  NEWS_HERO_DEFAULTS_TR,  NEWS_HERO_STATS_EN,  NEWS_HERO_STATS_TR,} from "./dummy-data"; export default function PageHeroDemo() {  return (    <Tabs defaultValue="default" className="w-full">      <SwipeTabsList>        <TabsTrigger value="default">Default</TabsTrigger>        <TabsTrigger value="stats">With HeroStats</TabsTrigger>        <TabsTrigger value="cta">CTA cluster</TabsTrigger>        <TabsTrigger value="density">Density</TabsTrigger>        <TabsTrigger value="i18n">Localized</TabsTrigger>      </SwipeTabsList>       <TabsContent value="default" className="mt-6 overflow-hidden rounded-2xl border border-border/50">        <PageHero          badge={NEWS_HERO_DEFAULTS.badge}          badgeIcon={NEWS_HERO_DEFAULTS.badgeIcon}          title={NEWS_HERO_DEFAULTS.title}          titleHighlight={NEWS_HERO_DEFAULTS.titleHighlight}          description={NEWS_HERO_DEFAULTS.description}        />      </TabsContent>       <TabsContent value="stats" className="mt-6 overflow-hidden rounded-2xl border border-border/50">        <PageHero          badge={NEWS_HERO_DEFAULTS.badge}          badgeIcon={NEWS_HERO_DEFAULTS.badgeIcon}          title={NEWS_HERO_DEFAULTS.title}          titleHighlight={NEWS_HERO_DEFAULTS.titleHighlight}          description={NEWS_HERO_DEFAULTS.description}        >          <HeroStats stats={NEWS_HERO_STATS_EN} />        </PageHero>      </TabsContent>       <TabsContent value="cta" className="mt-6 overflow-hidden rounded-2xl border border-border/50">        <PageHero          badge="New: v2.0"          title="Build faster"          titleHighlight="Ship sooner"          description="The component library for teams that move."        >          <div className="flex flex-wrap justify-center gap-4">            <Button size="lg" variant="secondary">              Get started            </Button>            <Button size="lg" variant="outline" className="bg-transparent text-primary-foreground border-primary-foreground/40 hover:bg-primary-foreground/10 hover:text-primary-foreground">              View docs            </Button>          </div>        </PageHero>      </TabsContent>       <TabsContent value="density" className="mt-6 space-y-4">        <p className="text-sm text-muted-foreground">          Three density levels — <code>compact</code> (40vh), <code>default</code> (70vh), <code>full</code> (100vh).          Below: compact only (full-screen variants would dominate the demo).        </p>        <div className="overflow-hidden rounded-2xl border border-border/50">          <PageHero            density="compact"            headingAs="h2"            title="Pricing"            description="Simple plans for teams of any size."          />        </div>      </TabsContent>       <TabsContent value="i18n" className="mt-6 overflow-hidden rounded-2xl border border-border/50">        <PageHero          badge={NEWS_HERO_DEFAULTS_TR.badge}          badgeIcon={NEWS_HERO_DEFAULTS_TR.badgeIcon}          title={NEWS_HERO_DEFAULTS_TR.title}          titleHighlight={NEWS_HERO_DEFAULTS_TR.titleHighlight}          description={NEWS_HERO_DEFAULTS_TR.description}        >          <HeroStats stats={NEWS_HERO_STATS_TR} />        </PageHero>      </TabsContent>    </Tabs>  );} 

Usage

When to use

Reach for PageHero as the top-of-page hero band on any landing or section: news landing, blog index, marketing page, docs site, app welcome screen. Composes a gradient background, accent badge chip, large title with optional highlight subline, description, and a flexible content slot.

Minimal example

import { PageHero } from "@/components/page-hero";

<PageHero
  badge="News & Updates"
  title="Latest Stories"
  titleHighlight="From Our Team"
  description="Insights and announcements."
/>;

With HeroStats

The HeroStats sub-component renders the typical icon-circle + bold value + small label triplet, designed for the white-on-gradient contrast inside the hero.

import { HeroStats, PageHero } from "@/components/page-hero";
import { Newspaper, TrendingUp, Clock } from "lucide-react";

<PageHero badge="News" title="Stories" description="Stay informed.">
  <HeroStats stats={[
    { icon: Newspaper, value: "500+", label: "Articles" },
    { icon: TrendingUp, value: "10K+", label: "Readers" },
    { icon: Clock, value: "Daily", label: "Updates" },
  ]} />
</PageHero>;

CTA cluster

<PageHero
  badge="New: v2.0"
  title="Build faster"
  titleHighlight="Ship sooner"
>
  <div className="flex justify-center gap-4">
    <Button size="lg" variant="secondary">Get started</Button>
    <Button size="lg" variant="outline">View docs</Button>
  </div>
</PageHero>;

Density variations

Three options via the density prop:

  • compact — min-h-[40vh]. Sub-page heroes, section dividers.
  • default — min-h-[70vh]. Most landing pages.
  • full — min-h-screen. Splash / welcome screens.

Custom title rendering

For mixed-color or italic-word titles beyond the simple title + titleHighlight combo, pass titleSlot:

<PageHero
  title="" // unused when titleSlot is provided
  titleSlot={
    <h1 className="text-5xl font-bold text-primary-foreground">
      The <em className="italic text-primary-foreground">future</em> of news
    </h1>
  }
  description="..."
/>;

Animation

Reveal animation runs on mount via the project-wide reveal-up CSS keyframe with 60ms staggered delays (badge → title → description → children). Respects prefers-reduced-motion automatically (free via the existing keyframe). Disable entirely with disableReveal={true}.

Accessibility

  • Section is a landmark with aria-labelledby pointing to the title id (auto-generated via useId).
  • Badge icon is aria-hidden; badge text is the meaningful label.
  • Heading semantic level configurable via headingAs={"h1" | "h2" | "h3"}. Default h1.
  • Reduced-motion users see content instantly (no transitions).

Features

  • Full-bleed gradient hero band — 3 density levels (compact 40vh / default 70vh / full 100vh)
  • 4-tier reveal stagger via project's `reveal-up` keyframe — badge / title / description / children, 60ms apart
  • Drops framer-motion peer dep (~100KB) — uses existing pro-ui CSS keyframe
  • `prefers-reduced-motion` respect inherited from the keyframe — content fades instantly for reduced-motion users
  • Badge chip (rounded-full, accent tint) with optional Lucide-style icon
  • Title-with-highlight pattern — second `<span>` rendered as a new line in accent color
  • `titleSlot` prop accepts ReactNode for rich custom rendering
  • `children` slot for stats / CTAs / search / breadcrumbs / anything
  • `HeroStats` sub-component exported separately for the icon-circle + value + label triplet pattern
  • Bottom SVG wave that fills with `--background` so the hero transitions cleanly
  • Subtle SVG noise pattern overlay on the gradient
  • ARIA — `aria-labelledby` wires section landmark to title id (useId)
  • Heading semantic level configurable via `headingAs` (h1 | h2 | h3)
  • `disableReveal` prop for SSR-only contexts
  • React.memo wrapped

Tags

page-heromarketingherolandingmigrationnews

Dependencies

npm peer deps: lucide-react@^1.11.0