Getting Started
Components
- All Components
- Animated Arrow
- Animated Save Button
- Animated Tabs
- Animated List/Grid View
- Animated Copy Button
- Animated 3D Folder
- Cursor-Tracking Glow Card
- Gradient Border Button
- Inline Edit Animation
- Animated OTP Input
- Liquid Metal Border
- Animated Password Input
- Interactive Pie Chart
- Typewriter
- Interactive World Map
Hero 2
A hero section with a dithering background and a floating navbar.
Turn every visit into a conversation.
Chatbot which understands your product and answers visitors, without adding to your support queue.
Installation
bash npx shadcn@latest add "https://ui.srb.codes/r/hero2"
Copy and paste the following code into your project.
"use client";
import { cn } from "@/lib/utils";
import { GradientBorderButton } from "@/components/components/gradient-border-button";
import { Button } from "@/components/ui/button";
import { Dithering } from "@paper-design/shaders-react";
import { ArrowRight } from "lucide-react";
import { type Transition, motion } from "motion/react";
import { useTheme } from "next-themes";
import { useEffect, useState } from "react";
const SHADER = {
colorFront: "#2196F3",
shape: "warp" as const,
type: "4x4" as const,
size: 1.5,
speed: 1,
fit: "cover" as const
} as const;
const SHADER_BACK_LIGHT = "#ffffff";
const SHADER_BACK_DARK = "#000000";
const stagger: Transition = {
type: "spring",
stiffness: 260,
damping: 24
};
function useShaderBackgroundColor() {
const { resolvedTheme } = useTheme();
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
if (!mounted) {
return SHADER_BACK_LIGHT;
}
return resolvedTheme === "dark" ? SHADER_BACK_DARK : SHADER_BACK_LIGHT;
}
function Hero2Background({ colorBack }: { colorBack: string }) {
return (
<div
aria-hidden
className="pointer-events-none absolute inset-0 overflow-hidden"
>
<Dithering
className="absolute inset-0 size-full opacity-20"
colorBack={colorBack}
colorFront={SHADER.colorFront}
shape={SHADER.shape}
type={SHADER.type}
size={SHADER.size}
speed={SHADER.speed}
fit={SHADER.fit}
/>
<div className="absolute inset-0 bg-linear-to-r from-background/95 via-background/55 to-background/20 md:from-background/90 md:via-background/40" />
</div>
);
}
export interface Hero2Props {
/** Extra classes forwarded to the outer section. */
className?: string;
}
export function Hero2({ className }: Hero2Props) {
const colorBack = useShaderBackgroundColor();
return (
<section
data-slot="hero2"
className={cn("relative isolate w-full overflow-hidden", className)}
>
<Hero2Background colorBack={colorBack} />
<div className="relative flex min-h-[70vh] w-full items-center px-6 py-20 sm:px-8 md:py-28 lg:py-32">
<div className="mx-auto w-full max-w-6xl">
<div className="max-w-xl">
<motion.h1
initial={{ opacity: 0, y: 16, filter: "blur(6px)" }}
animate={{ opacity: 1, y: 0, filter: "blur(0px)" }}
transition={{ ...stagger, delay: 0.08 }}
className="text-balance font-serif text-4xl font-medium tracking-tight text-foreground sm:text-5xl md:text-[3.25rem] md:leading-[1.08]"
>
Turn every visit into a{" "}
<span className="text-primary">conversation</span>.
</motion.h1>
<motion.p
initial={{ opacity: 0, y: 16, filter: "blur(6px)" }}
animate={{ opacity: 1, y: 0, filter: "blur(0px)" }}
transition={{ ...stagger, delay: 0.16 }}
className="text-muted-foreground mt-5 max-w-lg text-pretty text-base leading-relaxed sm:text-lg"
>
Chatbot which understands your product and answers visitors,
without adding to your support queue.
</motion.p>
<motion.div
initial={{ opacity: 0, y: 16, filter: "blur(6px)" }}
animate={{ opacity: 1, y: 0, filter: "blur(0px)" }}
transition={{ ...stagger, delay: 0.24 }}
className="mt-10 flex w-full flex-col gap-3 sm:w-auto sm:flex-row sm:items-center sm:gap-4"
>
<GradientBorderButton size="lg" asChild>
<a href="/docs">Get Started</a>
</GradientBorderButton>
<Button variant="outline" size="lg" asChild>
<a href="/docs" className="justify-center">
View Docs
<ArrowRight className="size-4" />
</a>
</Button>
</motion.div>
</div>
</div>
</div>
</section>
);
}
export Hero2;