Header 80
overlapping1 ColumnText Align CenterImage/Video BottomImage/Video CenterButtonsMultiple Images

Code
relume-header80.tsx
"use client";
import { useRef } from "react";
import { motion, useScroll, useSpring, useTransform } from "motion/react";
import clsx from "clsx";
import { Button, type ButtonProps } from "@/components/ui/button";
import { useMediaQuery } from "@/hooks/use-media-query";
type ImageProps = {
src: string;
alt?: string;
};
type Props = {
heading: string;
description: string;
buttons: ButtonProps[];
images: ImageProps[];
};
export type Header80Props = React.ComponentPropsWithoutRef<"section"> & Partial<Props>;
export const Header80 = (props: Header80Props) => {
const { heading, description, buttons, images } = {
...Header80Defaults,
...props,
};
const isMobile = useMediaQuery("(max-width: 767px)");
const sectionRef = useRef(null);
const { scrollYProgress } = useScroll({
target: sectionRef,
offset: ["start start", "end end"],
});
const animatedScrollYProgress = useSpring(scrollYProgress, {
bounce: 0,
});
const createTransform = (mobileValues: string[], desktopValues: string[]) =>
useTransform(scrollYProgress, [0, 1], isMobile ? mobileValues : desktopValues);
const yFirst = createTransform(["-12.5%", "-85%"], ["0%", "-85%"]);
const ySecond = createTransform(["-12.5%", "-85%"], ["0%", "-60%"]);
return (
<section ref={sectionRef} className="relative h-[150vh] px-[5%] md:h-[300vh]">
<div className="sticky top-0 h-screen overflow-hidden">
<div className="absolute top-0 right-auto bottom-0 left-0 z-10">
<motion.div className="flex flex-col gap-[26vw] pt-[70vh]" style={{ y: yFirst }}>
{images.slice(0, 4).map((image, index) => (
<div
key={index}
className={clsx("relative h-[35vw] pt-[120%] sm:h-auto", {
"w-[30vw] md:w-[28vw] lg:w-[22vw]": index === 0,
"left-[52vw] mt-[-46vw] w-[30vw] md:w-[28vw] lg:left-[58vw] lg:w-[22vw]":
index === 1,
"left-[4vw] mt-[-5vw] w-[28vw] md:w-[26vw] lg:w-[20vw]": index === 2,
"left-[64vw] mt-[-45vw] w-[26vw] md:w-[24vw] lg:w-[18vw]": index === 3,
})}
>
<img
src={image.src}
className="absolute inset-0 size-full rounded-image object-cover"
alt={image.alt}
/>
</div>
))}
</motion.div>
</div>
<motion.div
className="absolute top-0 right-0 bottom-0 left-auto z-0"
style={{ y: ySecond }}
>
<div className="flex flex-col gap-[26vw] pt-[70vh]">
{images.slice(4).map((image, index) => (
<div
key={index}
className={clsx("relative h-[35vw] pt-[120%] opacity-75 sm:h-auto", {
"w-[28vw] md:w-[26vw] lg:w-[20vw]": index === 0,
"right-[50vw] mt-[-44vw] w-[26vw] md:w-[24vw] lg:right-[54vw] lg:w-[18vw]":
index === 1,
})}
>
<img
src={image.src}
className="absolute inset-0 size-full rounded-image object-cover"
alt={image.alt}
/>
</div>
))}
</div>
</motion.div>
<div className="relative container flex h-full max-w-lg items-center pt-16 pb-24 text-center md:pt-24 lg:py-28">
<div>
<h1 className="mb-5 text-h1 font-bold md:mb-6">{heading}</h1>
<p className="relative z-20 text-medium">{description}</p>
<div className="relative z-20 mt-6 flex items-center justify-center gap-x-4 md:mt-8">
{buttons.map((button, index) => (
<Button key={index} {...button}>
{button.title}
</Button>
))}
</div>
</div>
</div>
<div className="absolute inset-0 -z-10 mt-[35rem] md:mt-[100vh]" />
</div>
</section>
);
};
export const Header80Defaults: Props = {
heading: "Medium length hero heading goes here",
description:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat.",
buttons: [
{
title: "Button",
},
{
title: "Button",
variant: "secondary",
},
],
images: [
{
src: "https://d22po4pjz3o32e.cloudfront.net/placeholder-image.svg",
alt: "Relume placeholder image 1",
},
{
src: "https://d22po4pjz3o32e.cloudfront.net/placeholder-image.svg",
alt: "Relume placeholder image 2",
},
{
src: "https://d22po4pjz3o32e.cloudfront.net/placeholder-image.svg",
alt: "Relume placeholder image 3",
},
{
src: "https://d22po4pjz3o32e.cloudfront.net/placeholder-image.svg",
alt: "Relume placeholder image 4",
},
{
src: "https://d22po4pjz3o32e.cloudfront.net/placeholder-image.svg",
alt: "Relume placeholder image 5",
},
{
src: "https://d22po4pjz3o32e.cloudfront.net/placeholder-image.svg",
alt: "Relume placeholder image 6",
},
],
};npm i @radix-ui/react-dialog @radix-ui/react-slot class-variance-authority@0.7.1 clsx@^2.1.1 motion@^12.15.0 relume-icons@1.3.0 tailwind-merge@^2.2.2


