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.

Open in
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 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

Build websites faster and 10x better than your competitors with Aceternity UI Pro

With the best in class components and templates, stand out from the crowd and get more attention to your website. Trusted by founders and entrepreneurs from all over the world.

Go Pro
This service exceeded our expectations, since not only was the development technically flawless, but Manu and his team also acted as strategic partners by encouraging us to add ...

Georg Weingartner

CMO at Renderwork

A product by Aceternity
Building in public at @mannupaaji