Features Section 1

Installation Steps

  1. Install Dependencies: Install the required dependencies using npm:

    npm install framer-motion
    
  2. Add animations to tailwind.config file:

tailwind.config.ts
module.exports = {
  theme: {
    extend: {
      animation: {
        "border-flow": "border-flow 3s ease-in-out infinite",
        "border-flow-reverse": "border-flow-reverse 3s ease-in-out infinite",
        "border-flow-vertical": "border-flow-vertical 3s ease-in-out infinite",
        "border-flow-vertical-reverse": "border-flow-vertical-reverse 3s ease-in-out infinite",
      },
      keyframes: {
          "border-flow": {
            "0%": { transform: "translateX(-100%)" },
            "100%": { transform: "translateX(100%)" },
          },
          "border-flow-reverse": {
            "0%": { transform: "translateX(100%)" },
            "100%": { transform: "translateX(-100%)" },
          },
          "border-flow-vertical": {
            "0%": { transform: "translateY(-100%)" },
            "100%": { transform: "translateY(100%)" },
          },
          "border-flow-vertical-reverse": {
            "0%": { transform: "translateY(100%)" },
            "100%": { transform: "translateY(-100%)" },
          },
        },
      },
    },
  },
};
  1. Copy this Component
FeaturesSection.tsx
"use client";
import { cn } from "@/lib/utils";
import {
  Brain,
  Code,
  Hammer,
  Lightbulb,
  Puzzle,
  Rocket,
  SquareTerminal,
  Users,
} from "lucide-react";
import { useEffect, useRef, useState } from "react";
import { motion, useAnimation } from "framer-motion";

const features = [
  {
    title: "Designed for Innovators",
    description:
      "Empowering coders, creators, and forward-thinkers to build the future.",
    icon: <Lightbulb className="size-6 text-muted-foreground" />,
  },

  {
    title: "Engineered for Builders",
    description:
      "For those who turn ideas into solutions, one line of code at a time.",
    icon: <Hammer className="size-6 text-muted-foreground" />,
  },
  {
    title: "Built for Developers",
    description: "Built for engineers, developers and indiehackers",
    icon: <SquareTerminal className="size-6 text-muted-foreground" />,
  },
  {
    title: "Crafted for Problem Solvers",
    description:
      "Supporting those who love to break down complex problems into elegant code.",
    icon: <Puzzle className="size-6 text-muted-foreground" />,
  },

  {
    title: "Optimized for Thinkers",
    description:
      "Made for those who push boundaries, dream big, and innovate relentlessly.",
    icon: <Brain className="size-6 text-muted-foreground" />,
  },

  {
    title: "Built for Code Enthusiasts",
    description:
      "For developers and creators driven by curiosity and a passion for tech.",
    icon: <Code className="size-6 text-muted-foreground" />,
  },

  {
    title: "Empowering Visionaries",
    description:
      "Fueling the aspirations of engineers, makers, and ambitious thinkers everywhere.",
    icon: <Rocket className="size-6 text-muted-foreground" />,
  },
  {
    title: "Tailored for Collaborators",
    description:
      "Enabling teams to connect, share knowledge, and create together.",
    icon: <Users className="size-6 text-muted-foreground" />,
  },
];

const containerVariants = {
  visible: {
    transition: {
      delayChildren: 0.5,
      staggerChildren: 0.5,
    },
  },
  hidden: {
    transition: {
      delayChildren: 0.5,
      staggerChildren: 0.5,
    },
  },
};

const childrenVariants = {
  visible: {
    opacity: 1,
    y: 0,
    filter: "blur(0px)",
    transition: {
      duration: 0.6,
      ease: "easeInOut",
    },
  },
  hidden: {
    opacity: 0,
    y: 10,
    filter: "blur(5px)",
    transition: {
      duration: 0.6,
      ease: "easeInOut",
    },
  },
};

const FeaturesSection = (): JSX.Element => {
  const containerRef = useRef<HTMLDivElement>(null);
  const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
  const [isHovering, setIsHovering] = useState(false);

  const handleMouseMove = (e: React.MouseEvent) => {
    if (!containerRef.current) return;

    const rect = containerRef.current.getBoundingClientRect();
    setMousePosition({
      x: e.clientX - rect.left,
      y: e.clientY - rect.top,
    });
  };

  return (
    <motion.section
      className="container flex flex-col max-w-7xl min-h-[350px] w-full justify-center mx-auto p-6 sm:py-14 items-center gap-y-12 lg:gap-y-16"
      variants={containerVariants}
      animate="visible"
      initial="hidden"
    >
      <div className="flex flex-col">
        <motion.div
          className="relative inline-flex w-min mx-auto h-8 select-none overflow-hidden rounded-full pt-[2px] px-[1.5px] pb-[1px] focus:outline-none"
          variants={{
            visible: {
              opacity: 1,
              y: 0,
            },
            hidden: {
              opacity: 0,
              y: 2,
            },
          }}
        >
          <span className="absolute inset-[-1000%] animate-[spin_3s_linear_infinite] bg-[conic-gradient(from_90deg_at_50%_50%,hsl(var(--primary))_0%,hsl(var(--muted))_50%,hsl(var(--primary))_100%)]" />
          <span className="inline-flex h-full w-full cursor-pointer items-center justify-center rounded-full bg-background px-4 py-1 font-medium text-sm text-foreground backdrop-blur-3xl">
            Features
          </span>
        </motion.div>
        <motion.h2
          className="leading-[1.1]! mt-6 mb-0 text-center tracking-tight font-semibold text-3xl text-foreground md:text-5xl lg:text-center"
          variants={childrenVariants}
        >
          Build like a Designer
        </motion.h2>
        <motion.p
          className="mt-4 max-w-lg text-center text-lg text-muted-foreground lg:text-center px-2"
          variants={childrenVariants}
        >
          Optiq UI makes your app look beautiful and easy to use with premade
          sections and components.
        </motion.p>
      </div>
      <motion.div
        className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 mx-auto"
        onMouseMove={handleMouseMove}
        onMouseEnter={() => setIsHovering(true)}
        onMouseLeave={() => setIsHovering(false)}
        ref={containerRef}
        transition={{ duration: 0.6, ease: "easeInOut" }}
        style={{
          background: isHovering
            ? `radial-gradient(200px circle at ${mousePosition.x}px ${mousePosition.y}px, hsl(var(--primary)) -200%, transparent 100%)`
            : "none",
        }}
      >
        {features.map((feature, index) => (
          <motion.div
            className={cn(
              "w-full h-full flex flex-col border-border relative py-10 group/card overflow-hidden max-w-7xl",
              {
                "lg:border-t": index % 3 === 0 && index < 4,
                "lg:border-b":
                  ((index % 4 === 0 || index === features.length - 1) &&
                    index >= 4) ||
                  index === 2 ||
                  index === 1,
                "lg:border-l":
                  (index >= 4 && index === features.length - 1) || index === 3,
                "lg:border-r": (index >= 4 && index % 4 === 0) || index === 0,
              }
            )}
            key={index}
            variants={{
              visible: {
                opacity: 1,
                y: 0,
                filter: "blur(0px)",
              },
              hidden: {
                opacity: 0,
                y: 10,
                filter: "blur(5px)",
              },
            }}
            transition={{ duration: 0.6, ease: "easeInOut" }}
          >
            {/* Animated border overlay */}
            <div className="absolute inset-0 pointer-events-none">
              <div className="absolute inset-0 opacity-0 group-hover/card:opacity-100 transition-opacity duration-300">
                {/* Top border */}
                <div className="absolute top-0 left-0 w-full h-px">
                  <div className="absolute w-full h-full animate-border-flow bg-gradient-to-r from-transparent via-primary to-transparent" />
                </div>
                {/* Right border */}
                <div className="absolute top-0 right-0 w-px h-full">
                  <div className="absolute w-full h-full animate-border-flow-vertical bg-gradient-to-b from-transparent via-primary to-transparent" />
                </div>
                {/* Bottom border */}
                <div className="absolute bottom-0 left-0 w-full h-px">
                  <div className="absolute w-full h-full animate-border-flow-reverse bg-gradient-to-r from-transparent via-primary to-transparent" />
                </div>
                {/* Left border */}
                <div className="absolute top-0 left-0 w-px h-full">
                  <div className="absolute w-full h-full animate-border-flow-vertical-reverse bg-gradient-to-b from-transparent via-primary to-transparent" />
                </div>
              </div>
            </div>

            <div className="opacity-0 group-hover/card:opacity-100 transition duration-200 absolute inset-0 h-full w-full bg-gradient-to-t from-primary/35 dark:from-primary/30 to-transparent"></div>
            <div
              className={cn(
                "mb-4 mt-2 px-10 transition-all duration-200 group-hover/card:translate-x-2",
                {
                  "lg:group-hover/card:-translate-x-2 lg:group-hover/card:-translate-y-0":
                    index === 2 || index === 6,
                  "lg:group-hover/card:translate-x-2 lg:group-hover/card:-translate-y-0":
                    index === 1 || index === 5,
                  "lg:group-hover/card:-translate-y-2 lg:group-hover/card:translate-x-0":
                    index === 4 || index === features.length - 1,
                  "lg:group-hover/card:translate-y-2 lg:group-hover/card:translate-x-0":
                    index === 0 || index === 3,
                }
              )}
            >
              {feature.icon}
            </div>
            <div
              className={cn(
                "px-10 z-10 transition-all duration-200 group-hover/card:translate-x-2",
                {
                  "lg:group-hover/card:-translate-x-2 lg:group-hover/card:-translate-y-0":
                    index === 2 || index === 6,
                  "lg:group-hover/card:translate-x-2 lg:group-hover/card:-translate-y-0":
                    index === 1 || index === 5,
                  "lg:group-hover/card:-translate-y-2 lg:group-hover/card:translate-x-0":
                    index === 4 || index === features.length - 1,
                  "lg:group-hover/card:translate-y-2 lg:group-hover/card:translate-x-0":
                    index === 0 || index === 3,
                }
              )}
            >
              <h2 className="text-xl font-bold text-foreground relative text-left mt-0">
                {feature.title}
              </h2>
              <p className="text-muted-foreground text-md max-w-xs pr-4 text-left mt-2">
                {feature.description}
              </p>
            </div>
            <div
              className={cn(
                "absolute  bg-neutral-700 transition-all duration-200 group-hover/card:h-[0.4rem] group-hover/card:bg-primary",
                {
                  "lg:left-[calc(50%-3rem)] lg:top-0 rounded-tr-full rounded-br-full lg:rounded-br-full lg:rounded-bl-full lg:rounded-tr-none lg:rounded-tl-none w-1 h-[6rem] lg:w-[6rem] lg:h-1 lg:group-hover/card:w-[6.5rem] lg:group-hover/card:h-1 group-hover/card:h-[6.5rem]":
                    index === 0 || index === 3,
                  "lg:left-0 lg:top-[calc(50%-3rem)] rounded-tr-full rounded-br-full w-1 h-[6rem] group-hover/card:h-[6.5rem]":
                    index === 1 || index === 5,
                  "lg:right-0 lg:top-[calc(50%-3rem)] rounded-tr-full rounded-br-full lg:rounded-tl-full lg:rounded-bl-full lg:rounded-tr-none lg:rounded-br-none w-1 h-[6rem] group-hover/card:h-[6.5rem]":
                    index === 2 || index === 6,
                  "lg:left-[calc(50%-3rem)] lg:bottom-0 rounded-tr-full rounded-br-full lg:rounded-br-none lg:rounded-bl-none lg:rounded-tr-full lg:rounded-tl-full lg:w-[6rem] lg:h-1 w-1 h-[6rem] lg:group-hover/card:w-[6.5rem] lg:group-hover/card:h-1 group-hover/card:h-[6.5rem]":
                    index === 4 || index === features.length - 1,
                }
              )}
            ></div>
          </motion.div>
        ))}
      </motion.div>
    </motion.section>
  );
};

export default FeaturesSection;