Eunary UI, a modern component library built with React, Tailwind CSS, and Motion, providing accessible and animated components

Floating Elements Card

Interactive card component with stacked layered effects and animated floating icons that elegantly appear around the content on hover.

@hemantsh03
avatar illustration representing @hemantsh03.

Hemant Sharma

Full-stack Developer

React • Node.js • TypeScript

⭐ 4.9/569 projects

Recent Project

EunaryUI

Elegant modern UI components powered by motion, fluid and responsive.

NextJSMotionTailwind
Eunary UI, a modern component library built with React, Tailwind CSS, and Motion, providing accessible and animated components

Specialized in creating modern web applications.

Eunary UI, a modern component library built with React, Tailwind CSS, and Motion, providing accessible and animated components

Installation

Install dependencies

npm install class-variance-authority motion clsx tailwind-merge

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/floating-elements-card.tsx
'use client';

import { cn } from '@/lib/utils';
import { motion } from 'motion/react';

const SPRING_CONFIG = {
    type: 'spring' as const,
    stiffness: 500,
    damping: 25,
};

const ICON_SPRING_CONFIG = {
    type: 'spring' as const,
    stiffness: 500,
    damping: 30,
};

const cardParentVariant = {
    initial: {},
    animate: {
        transition: {
            staggerChildren: 0.01,
        },
    },
};

// Generate card variants dynamically
const createCardVariant = (yOffset: number, scale = 1) => ({
    initial: { y: 0, scale: scale === 1 ? undefined : 0.9 },
    animate: {
        y: yOffset,
        scale,
        transition: SPRING_CONFIG,
    },
});

const cardVariants = [
    createCardVariant(210),
    createCardVariant(190, 1),
    createCardVariant(170, 1),
];

const iconParentVariant = {
    initial: { y: 0 },
    animate: {
        transition: {
            staggerChildren: 0.1,
        },
    },
};

const createIconVariant = (x: number, y: number, rotate: number) => ({
    initial: {
        y: 0,
        x: 0,
        opacity: 0,
        filter: 'blur(8px)',
        scale: 0.5,
    },
    animate: {
        y,
        x,
        opacity: 1,
        filter: 'blur(0px)',
        scale: 1,
        rotate,
        transition: ICON_SPRING_CONFIG,
    },
});

// Card configuration
const cardConfigs = [
    { width: 'w-[27rem]', zIndex: 'z-20', hasContent: true },
    { width: 'w-[25rem]', zIndex: 'z-10', hasContent: false },
    { width: 'w-[23rem]', zIndex: 'z-0', hasContent: false },
];

type iconLink = {
    icon: React.ReactNode;
    link: string;
};

interface Props {
    children: React.ReactNode;
    icons: iconLink[];
}

export const FloatingElementsCard = ({ children, icons = [] }: Props) => {
    const iconConfigs = [
        {
            variant: createIconVariant(-180, -120, -30),
            ...icons[0],
            key: '0',
        },
        {
            variant: createIconVariant(-65, -160, -15),
            ...icons[1],
            key: '1',
        },
        {
            variant: createIconVariant(65, -160, 15),
            ...icons[2],
            key: '2',
        },
        {
            variant: createIconVariant(180, -120, 30),
            ...icons[3],
            key: '3',
        },
    ].filter(Boolean);

    return (
        <motion.div
            initial="initial"
            whileHover="animate"
            className="group relative flex h-[30rem] w-[32rem] flex-col items-center justify-center gap-4 overflow-hidden px-20"
        >
            <motion.div
                variants={cardParentVariant}
                className="relative flex items-center justify-center"
            >
                {cardConfigs.map((config, index) => (
                    <motion.div
                        key={`card-${index}`}
                        variants={cardVariants[index]}
                        className={cn(
                            'absolute h-[25rem] rounded-3xl border border-neutral-300/50 bg-gradient-to-br from-neutral-50 to-neutral-100 shadow-[0_0_10px_2px_rgba(83,83,83,0.15)] backdrop-blur-xl group-hover:shadow-[0_-5px_10px_2px_rgba(83,83,83,0.15)] dark:border-neutral-700/50 dark:from-neutral-800/90 dark:to-neutral-900/90',
                            config.width,
                            config.zIndex,
                            config.hasContent ? 'p-4' : ''
                        )}
                    >
                        {config.hasContent && children}
                    </motion.div>
                ))}
            </motion.div>

            <motion.div
                className="relative inset-0 flex items-center justify-center gap-6"
                variants={iconParentVariant}
            >
                {iconConfigs.map(({ icon, link, variant, key }) => (
                    <motion.div
                        key={key}
                        className="absolute"
                        variants={variant}
                    >
                        <a
                            href={link || 'https://ui.eunary.com'}
                            target="_blank"
                            className={cn(
                                'flex h-22 w-22 items-center justify-center rounded-full border border-slate-200 bg-gradient-to-br from-white to-slate-100 shadow-lg shadow-neutral-900/50 backdrop-blur-sm dark:border-neutral-600/50 dark:from-neutral-700 dark:to-neutral-800 dark:shadow-neutral-600/50',
                                'origin-center transition-all duration-200 ease-out hover:scale-110'
                            )}
                        >
                            {icon}
                        </a>
                    </motion.div>
                ))}
            </motion.div>
            <div className="absolute bottom-0 z-50 hidden h-24 w-full bg-gradient-to-t from-white to-transparent group-hover:block dark:from-black"></div>
        </motion.div>
    );
};

Props

Use the following props to customize the floating elements and card content.

PropTypeDescription
childrenReact.ReactNodeThe content to be displayed inside the main (front) card.
icons{ icon: React.ReactNode; link: string }[]Array of icon objects with icon element and link URL that float around the card on hover.

Explore more components with Eunary

Discover and experiment with a variety of components to craft a stunning and seamless experience for your product.

Eunary UI, a modern component library built with React, Tailwind CSS, and Motion, providing accessible and animated components

Eunary

UI

Product by Eunary

Building in public by Hemant Sharma