React component
A full-screen agency hero with social proof, a stats marquee, and a direct call to action.
We take your big ideas and turn them into clear, winning strategies. From setting up your company to scaling it worldwide, we're here every step of the way.
Create and integrate a responsive React hero component in an existing codebase.
Project requirements:
- Use the existing shadcn project structure.
- Use Tailwind CSS and TypeScript.
- Place shared UI components in `/components/ui`.
- Use Lucide React for icons.
- Use a known Unsplash image for the background.
- Preserve the existing application theme outside this component.
Before implementation:
1. Inspect the project structure and package dependencies.
2. Confirm the default component and global style paths.
3. Identify missing UI dependencies and install only what is needed.
4. Keep interactive code inside focused client components.
Add this counter example as `components/ui/hero.tsx`:
```tsx
"use client";
import { cn } from "@/lib/utils";
import { useState } from "react";
export const Component = () => {
const [count, setCount] = useState(0);
return (
<div className={cn("flex flex-col items-center gap-4 rounded-lg p-4")}>
<h1 className="mb-2 text-2xl font-bold">Component Example</h1>
<h2 className="text-xl font-semibold">{count}</h2>
<div className="flex gap-2">
<button onClick={() => setCount((prev) => prev - 1)}>-</button>
<button onClick={() => setCount((prev) => prev + 1)}>+</button>
</div>
</div>
);
};
```
Add the following hero as `components/ui/demo.tsx`. Reuse the project Avatar and Button components and add a reusable Marquee component if one does not exist.
```tsx
"use client";
import { ArrowRight } from "lucide-react";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
import { Marquee } from "@/components/ui/marquee";
const teamAvatars = [
{
initials: "JD",
src: "https://res.cloudinary.com/doonkheo8/image/upload/v1770279333/a1.jpg",
},
{
initials: "HJ",
src: "https://res.cloudinary.com/doonkheo8/image/upload/v1770279333/a2.jpg",
},
{
initials: "PI",
src: "https://res.cloudinary.com/doonkheo8/image/upload/v1770279333/a3.jpg",
},
{
initials: "KD",
src: "https://res.cloudinary.com/doonkheo8/image/upload/v1770279333/a4.jpg",
},
{
initials: "LD",
src: "https://res.cloudinary.com/doonkheo8/image/upload/v1770279333/a5.jpg",
},
];
const stats = [
{ emoji: "🚀", label: "IN CLIENT REVENUE GENERATED", value: "$5M+" },
{ emoji: "📈", label: "BUSINESSES LAUNCHED", value: "200+" },
{ emoji: "💰", label: "SAVED IN OPERATIONAL COSTS", value: "$500K+" },
];
function AvatarStack() {
return (
<div className="flex -space-x-3">
{teamAvatars.map((member, index) => (
<Avatar
className="size-13 border-2 border-primary bg-neutral-800"
key={member.initials}
style={{ zIndex: teamAvatars.length - index }}
>
<AvatarImage alt={`Team member ${index + 1}`} src={member.src} />
<AvatarFallback className="bg-neutral-700 text-xs text-white">
{member.initials}
</AvatarFallback>
</Avatar>
))}
</div>
);
}
function StatsMarquee() {
return (
<Marquee
className="border-y border-white/10 bg-black/30 py-2 backdrop-blur-sm [--duration:30s] [--gap:2rem]"
pauseOnHover
repeat={4}
>
{stats.map((stat) => (
<div className="flex items-center gap-3 whitespace-nowrap" key={stat.label}>
<span className="font-mono text-sm font-bold tracking-wide text-primary">
{stat.value}
</span>
<span className="font-mono text-sm font-medium uppercase tracking-[0.15em] text-white/70">
{stat.label}
</span>
<span className="text-base">{stat.emoji}</span>
</div>
))}
</Marquee>
);
}
export default function Hero() {
return (
<section className="prompt-hero-demo relative flex min-h-[100dvh] w-full flex-col items-start justify-end overflow-hidden">
<div
className="absolute inset-0 bg-cover bg-center"
style={{
backgroundImage:
"url(https://images.unsplash.com/photo-1541746972996-4e0b0f43e02a?auto=format&fit=crop&w=1600&q=85)",
}}
>
<div className="absolute inset-0 bg-black/50" />
</div>
<div className="relative z-10 w-full max-w-4xl px-4 text-white sm:px-8 lg:px-16">
<div className="space-y-4">
<AvatarStack />
<StatsMarquee />
</div>
</div>
<div className="relative z-10 w-full px-4 pb-16 sm:px-8 sm:pb-24 lg:px-16 lg:pb-32">
<div className="flex flex-col gap-6 sm:flex-row sm:items-end">
<div className="w-full space-y-4 sm:w-1/2">
<h1 className="text-4xl font-medium leading-[1.05] tracking-tight text-white sm:text-5xl md:text-6xl lg:text-7xl">
We <span className="text-primary">think</span>, you{" "}
<span className="text-primary">grow</span>
<br />
<span className="text-white">- that's the deal</span>
</h1>
<Button className="rounded-none py-0 pr-0 text-lg font-normal text-black">
Get Template
<span className="border-l border-neutral-500 p-3">
<ArrowRight aria-hidden="true" />
</span>
</Button>
</div>
<div className="w-full sm:w-1/2">
<p className="text-base italic text-primary sm:text-right md:text-2xl">
We take your big ideas and turn them into clear, winning strategies.
From setting up your company to scaling it worldwide, we're here every step of the way.
</p>
</div>
</div>
</div>
</section>
);
}
```
Extend the Tailwind 4 global stylesheet with the animation tokens and keyframes below. Scope the lime primary color to `.prompt-hero-demo` so the rest of the application keeps its existing theme.
```css
@theme inline {
--animate-marquee: marquee var(--duration) infinite linear;
--animate-marquee-vertical: marquee-vertical var(--duration) linear infinite;
}
.prompt-hero-demo {
--primary: oklch(0.95 0.16 118.89);
--primary-foreground: oklch(0.18 0 0);
}
@keyframes marquee {
from {
transform: translateX(0);
}
to {
transform: translateX(calc(-100% - var(--gap)));
}
}
@keyframes marquee-vertical {
from {
transform: translateY(0);
}
to {
transform: translateY(calc(-100% - var(--gap)));
}
}
@media (prefers-reduced-motion: reduce) {
.animate-marquee,
.animate-marquee-vertical {
animation-play-state: paused;
}
}
```
Expected responsive behavior:
- Use `min-h-[100dvh]` for a stable full-height hero.
- Stack the headline and supporting text on small screens.
- Use a two-column layout from the `sm` breakpoint.
- Keep the marquee clipped inside the hero.
- Preserve readable contrast over the image at every breakpoint.
Verify the result with TypeScript, ESLint, and a production build.