Hero Highlight
A background effect with a text highlight component, perfect for hero sections.
With insomnia, nothing's real. Everything is far away. Everything is a copy, of a copy, of a copy.
Installation
Install dependencies
npm i motion clsx tailwind-merge
Add util file
import { ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
Copy the source code
components/ui/hero-highlight.tsx
"use client";
import { cn } from "@/lib/utils";
import { useMotionValue, motion, useMotionTemplate } from "motion/react";
import React from "react";
export const HeroHighlight = ({
children,
className,
containerClassName,
}: {
children: React.ReactNode;
className?: string;
containerClassName?: string;
}) => {
let mouseX = useMotionValue(0);
let mouseY = useMotionValue(0);
// SVG patterns for different states and themes
const dotPatterns = {
light: {
default: `url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32' width='16' height='16' fill='none'%3E%3Ccircle fill='%23d4d4d4' id='pattern-circle' cx='10' cy='10' r='2.5'%3E%3C/circle%3E%3C/svg%3E")`,
hover: `url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32' width='16' height='16' fill='none'%3E%3Ccircle fill='%236366f1' id='pattern-circle' cx='10' cy='10' r='2.5'%3E%3C/circle%3E%3C/svg%3E")`,
},
dark: {
default: `url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32' width='16' height='16' fill='none'%3E%3Ccircle fill='%23404040' id='pattern-circle' cx='10' cy='10' r='2.5'%3E%3C/circle%3E%3C/svg%3E")`,
hover: `url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32' width='16' height='16' fill='none'%3E%3Ccircle fill='%238183f4' id='pattern-circle' cx='10' cy='10' r='2.5'%3E%3C/circle%3E%3C/svg%3E")`,
},
};
function handleMouseMove({
currentTarget,
clientX,
clientY,
}: React.MouseEvent<HTMLDivElement>) {
if (!currentTarget) return;
let { left, top } = currentTarget.getBoundingClientRect();
mouseX.set(clientX - left);
mouseY.set(clientY - top);
}
return (
<div
className={cn(
"group relative flex h-[40rem] w-full items-center justify-center bg-white dark:bg-black",
containerClassName,
)}
onMouseMove={handleMouseMove}
>
<div
className="pointer-events-none absolute inset-0 dark:hidden"
style={{
backgroundImage: dotPatterns.light.default,
}}
/>
<div
className="pointer-events-none absolute inset-0 hidden dark:block"
style={{
backgroundImage: dotPatterns.dark.default,
}}
/>
<motion.div
className="pointer-events-none absolute inset-0 opacity-0 transition duration-300 group-hover:opacity-100 dark:hidden"
style={{
backgroundImage: dotPatterns.light.hover,
WebkitMaskImage: useMotionTemplate`
radial-gradient(
200px circle at ${mouseX}px ${mouseY}px,
black 0%,
transparent 100%
)
`,
maskImage: useMotionTemplate`
radial-gradient(
200px circle at ${mouseX}px ${mouseY}px,
black 0%,
transparent 100%
)
`,
}}
/>
<motion.div
className="pointer-events-none absolute inset-0 hidden opacity-0 transition duration-300 group-hover:opacity-100 dark:block"
style={{
backgroundImage: dotPatterns.dark.hover,
WebkitMaskImage: useMotionTemplate`
radial-gradient(
200px circle at ${mouseX}px ${mouseY}px,
black 0%,
transparent 100%
)
`,
maskImage: useMotionTemplate`
radial-gradient(
200px circle at ${mouseX}px ${mouseY}px,
black 0%,
transparent 100%
)
`,
}}
/>
<div className={cn("relative z-20", className)}>{children}</div>
</div>
);
};
export const Highlight = ({
children,
className,
}: {
children: React.ReactNode;
className?: string;
}) => {
return (
<motion.span
initial={{
backgroundSize: "0% 100%",
}}
animate={{
backgroundSize: "100% 100%",
}}
transition={{
duration: 2,
ease: "linear",
delay: 0.5,
}}
style={{
backgroundRepeat: "no-repeat",
backgroundPosition: "left center",
display: "inline",
}}
className={cn(
`relative inline-block rounded-lg bg-gradient-to-r from-indigo-300 to-purple-300 px-1 pb-1 dark:from-indigo-500 dark:to-purple-500`,
className,
)}
>
{children}
</motion.span>
);
};
Props
HeroHighlight
Props
Prop | Type | Default | Description |
---|---|---|---|
children | React.ReactNode | N/A | The content to be displayed inside the HeroHighlight component. |
className | string (optional) | N/A | Additional CSS classes to apply to the child component for styling. |
containerClassName | string (optional) | N/A | Additional CSS classes to apply to the container component for styling. |
Highlight
Props
Prop | Type | Default | Description |
---|---|---|---|
children | React.ReactNode | N/A | The content to be highlighted. |
className | string (optional) | N/A | Additional CSS classes to apply to the Highlight component for styling. |
Inspiration for this component is taken from Designboost's Homepage
Get beautiful, hand-crafted templates and components with Aceternity UI Pro
Professional, beautiful and elegant templates for your business. Get the best component packs and templates with Aceternity UI Pro.
I'd highly recommend working with Manu on a site redesign. We came to Manu with a basic website shell. Manu quickly took our rough concept and transformed it into a polished, user-friendly website....
Ray Thai
Head of Product at Fireworks