Introducing Aceternity UI Pro - Premium component packs and templates to build awesome websites.
Logo

Focus Cards

Hover over the card to focus on it, blurring the rest of the cards.

Forest Adventure
Forest Adventure
Valley of life
Valley of life
Sala behta hi jayega
Sala behta hi jayega
Camping is for pros
Camping is for pros
The road not taken
The road not taken
The First Rule
The First Rule

Installation

Install dependencies

npm i framer-motion clsx tailwind-merge @tabler/icons-react

Add util file

lib/utils.ts
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/focus-cards.tsx

"use client";
import Image from "next/image";
import React, { useState } from "react";
import { cn } from "@/lib/utils";
 
export const Card = React.memo(
  ({
    card,
    index,
    hovered,
    setHovered,
  }: {
    card: any;
    index: number;
    hovered: number | null;
    setHovered: React.Dispatch<React.SetStateAction<number | null>>;
  }) => (
    <div
      onMouseEnter={() => setHovered(index)}
      onMouseLeave={() => setHovered(null)}
      className={cn(
        "rounded-lg relative bg-gray-100 dark:bg-neutral-900 overflow-hidden h-60 md:h-96 w-full transition-all duration-300 ease-out",
        hovered !== null && hovered !== index && "blur-sm scale-[0.98]"
      )}
    >
      <Image
        src={card.src}
        alt={card.title}
        fill
        className="object-cover absolute inset-0"
      />
      <div
        className={cn(
          "absolute inset-0 bg-black/50 flex items-end py-8 px-4 transition-opacity duration-300",
          hovered === index ? "opacity-100" : "opacity-0"
        )}
      >
        <div className="text-xl md:text-2xl font-medium bg-clip-text text-transparent bg-gradient-to-b from-neutral-50 to-neutral-200">
          {card.title}
        </div>
      </div>
    </div>
  )
);
 
Card.displayName = "Card";
 
type Card = {
  title: string;
  src: string;
};
 
export function FocusCards({ cards }: { cards: Card[] }) {
  const [hovered, setHovered] = useState<number | null>(null);
 
  return (
    <div className="grid grid-cols-1 md:grid-cols-3 gap-10 max-w-5xl mx-auto md:px-8 w-full">
      {cards.map((card, index) => (
        <Card
          key={card.title}
          card={card}
          index={index}
          hovered={hovered}
          setHovered={setHovered}
        />
      ))}
    </div>
  );
}

Props

ComponentPropTypeDescription
CardcardCardThe card object containing title and src properties
CardindexnumberThe index of the card in the array
Cardhoverednumber | nullThe index of the currently hovered card, or null if no card is hovered
CardsetHoveredReact.Dispatch<React.SetStateAction<number | null>>Function to update the hovered state
FocusCardscardsCard[]An array of Card objects to be rendered

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.

Check website

Manu is a genius. He is open-minded, curious and deeply invested in the projects he chooses to work on. He takes your vision and brings it to life -- and is a true partner in th...

Meru Gokhale

Founder at Editorially, Editrix

A product by Aceternity
Building in public at @mannupaaji