Page Intro
The compact first section of an inner page: its one h1, a line and its actions, plain or on a tinted band.
npx shadcn@latest add @vibebox/hero-page-introControls
<HeroPageIntro />About
A new block for Launchpad's inner pages, replacing the site kit's page hero. It keeps the full hero base, so an inner page can be swapped to a full hero without losing copy.
Use it when
- The first section of any page except the home page.
Skip it when
- The home page: use a full hero.
Install
- 1Add the VibeBox registry to
components.json:{ "registries": { "@vibebox": "https://motion.vibeboxph.com/r/{name}.json" } } - 2Add the block with the shadcn CLI:
npx shadcn@latest add @vibebox/hero-page-intro - 3Use it:
import { HeroPageIntro } from "@/components/vibebox/hero-page-intro"; import { home } from "@/content/pages/home"; <HeroPageIntro content={home.intro} variant="plain" id="top" />
Code
2 filescomponents/vibebox/hero-page-intro/index.tsx
/**
* VibeBox Motion · Page Intro
* Copyright (c) 2026 VibeBox. Licensed under the VibeBox Motion Free License:
* https://motion.vibeboxph.com/license
* Use it in unlimited personal, commercial and client projects.
* Do not sell or redistribute it as a component, kit, template or builder.
*/
import { Actions, Container, Eyebrow, headingId, Media, Section, SlotText, type BlockProps } from "@/lib/vibebox/block-kit";
import { cn } from "@/lib/utils";
import type { Content, Variant } from "./schema";
/*
* The first section of an inner page (Services, About, Pricing): the page's one h1, a line, and
* its actions, compact so the page's content starts high. `band` sets it on a tinted panel.
*/
export type HeroPageIntroProps = BlockProps<Content, Variant>;
export function HeroPageIntro({ content, variant = "plain", id, tone, className }: HeroPageIntroProps) {
const band = variant === "band";
return (
<Section slug="hero-page-intro" variant={variant} id={id} tone={tone} labelledBy={headingId(id)} spacing={false} className={cn("pt-[clamp(40px,6vw,88px)] pb-[clamp(24px,4vw,56px)]", className)}>
<Container>
<div
className={cn(
"grid grid-cols-[minmax(0,1fr)] items-end gap-8",
content.media && "md:grid-cols-[minmax(0,1fr)_minmax(0,0.42fr)]",
band && "rounded-xl bg-[linear-gradient(140deg,color-mix(in_oklab,var(--spectrum-2)_10%,var(--card)),var(--card))] p-6 ring-1 ring-border sm:p-10 lg:p-12",
)}
>
<div className="grid gap-5">
<Eyebrow value={content.eyebrow} />
<SlotText as="h1" value={content.heading} path="heading" id={headingId(id)} reveal className="font-display text-[clamp(2.4rem,1.4rem+3.6vw,4.5rem)] leading-[1.02] font-semibold tracking-[-0.035em] text-balance" />
<SlotText as="p" value={content.lead} path="lead" className="max-w-[60ch] text-[clamp(1.02rem,1.2vw,1.15rem)] leading-relaxed text-pretty text-muted-foreground" />
<Actions primary={content.primaryAction} secondary={content.secondaryAction} className="mt-1" />
</div>
{content.media && (
<div className="hidden aspect-[4/3] overflow-hidden rounded-xl ring-1 ring-border md:block">
<Media image={content.media} priority sizes="30vw" />
</div>
)}
</div>
</Container>
</Section>
);
}components/vibebox/hero-page-intro/schema.ts
/**
* VibeBox Motion · Page Intro
* Copyright (c) 2026 VibeBox. Licensed under the VibeBox Motion Free License:
* https://motion.vibeboxph.com/license
* Use it in unlimited personal, commercial and client projects.
* Do not sell or redistribute it as a component, kit, template or builder.
*/
import { sections, type z } from "@/lib/vibebox/content";
export const variants = ["plain", "band"] as const;
export type Variant = (typeof variants)[number];
/* The hero base, kept whole so an inner page can swap to a full hero; the intro shows its media small. */
export const content = sections.hero;
export type Content = z.infer<typeof content>;Content
Typed slots from schema.ts. Facts (hours, prices, quotes, names) come only from the business; until then they render as fill-ins.
| Slot | Label | Type | Limit | Fact |
|---|---|---|---|---|
| eyebrow | Kicker | text | 32 chars | — |
| heading | Headline | text | 80 chars | — |
| lead | Intro | text | 160 chars | — |
| primaryAction | Main button | action | 24 chars | — |
| secondaryAction | Second button | action | 24 chars | — |
| media | Image | image | — | — |
Variants
Plaindefault
plain
The heading on the page surface.
Band
band
The heading on a softly tinted panel.
Accessibility and motion
- Keyboard
- The actions.
- Screen readers
- The page's one h1, its line and actions.
- Touch
- Nothing depends on hover.
- Reduced motion
- Nothing moves.
Edge cases and limits
- An 80-character heading wraps to three lines on phones.
Related

Bento Hero
FreeThe promise beside a three-tile mosaic: a tall photo, a second image and a card of what the business offers.
Heroes block · Server

Centered Hero
FreeOne centred promise with its actions and highlights, the image below, on a plain, haloed or gradient panel ground.
Heroes block · Server

Editorial Hero
FreeA magazine opening: a large serif headline, the intro and actions, tags, and the photo framed tall or set as a band.
Heroes block · Server