Docs
Feature Grid 4-Column

Feature Grid 4-Column

A professional 4-column feature grid with gradient icons, metrics, and interactive elements. Perfect for showcasing 8+ features with a clean, modern design.

Platform

Developer-First Infrastructure

A complete toolkit for building modern applications. Scalable, secure, and designed for developer productivity.

New

Edge Functions

Run code at the edge with zero cold starts and global distribution.

View docs

Global Database

Serverless database with automatic replication and instant branching.

Start building
Secure

Enterprise Auth

Secure authentication with SAML, SSO, and MFA out of the box.

Learn more

Auto-Scaling

Infrastructure that scales automatically with your traffic spikes.

View pricing

Preview Deploys

Automatic preview environments for every pull request you make.

See demo

Instant Rollbacks

Revert to any previous deployment version in milliseconds.

Read guide
Fast

Serverless Compute

Run complex workloads without managing a single server.

Get started

Global CDN

Deliver content faster with our intelligent global edge network.

View map

Installation

Copy and paste the following code into your project.

"use client";
 
import { motion, useMotionTemplate, useMotionValue } from "framer-motion";
import { ArrowRight, LucideIcon } from "lucide-react";
import { MouseEvent } from "react";
import { cn } from "@/lib/utils";
 
interface Feature {
  icon: LucideIcon;
  title: string;
  description: string;
  badge?: string;
  href?: string;
  cta?: string;
}
 
interface FeatureGrid4ColProps {
  badge?: string;
  headline: string;
  description?: string;
  features: Feature[];
  className?: string;
}
 
function FeatureCard({ feature, index }: { feature: Feature; index: number }) {
  const mouseX = useMotionValue(0);
  const mouseY = useMotionValue(0);
 
  function handleMouseMove({ currentTarget, clientX, clientY }: MouseEvent) {
    const { left, top } = currentTarget.getBoundingClientRect();
    mouseX.set(clientX - left);
    mouseY.set(clientY - top);
  }
 
  const Icon = feature.icon;
 
  return (
    <motion.div
      initial={{ opacity: 0, y: 20 }}
      whileInView={{ opacity: 1, y: 0 }}
      viewport={{ once: true }}
      transition={{ duration: 0.5, delay: index * 0.05 }}
      className="group relative h-full"
      onMouseMove={handleMouseMove}
    >
      <div className="relative h-full overflow-hidden rounded-2xl border border-zinc-800 bg-zinc-900/30 p-6 transition-colors hover:bg-zinc-900/50">
        {/* Hover Glow Effect */}
        <motion.div
          className="pointer-events-none absolute -inset-px opacity-0 transition duration-300 group-hover:opacity-100"
          style={{
            background: useMotionTemplate`
              radial-gradient(
                350px circle at ${mouseX}px ${mouseY}px,
                rgba(59, 130, 246, 0.1),
                transparent 80%
              )
            `,
          }}
        />
 
        {/* Border Gradient on Hover */}
        <motion.div
          className="pointer-events-none absolute -inset-px rounded-2xl opacity-0 transition duration-300 group-hover:opacity-100"
          style={{
            background: useMotionTemplate`
              radial-gradient(
                600px circle at ${mouseX}px ${mouseY}px,
                rgba(59, 130, 246, 0.4),
                transparent 40%
              )
            `,
            maskImage:
              "linear-gradient(black, black) content-box, linear-gradient(black, black)",
            maskComposite: "exclude",
            WebkitMaskComposite: "xor",
            padding: "1px",
          }}
        />
 
        <div className="relative z-10 flex h-full flex-col">
          <div className="mb-4 flex items-center justify-between">
            <div className="inline-flex items-center justify-center rounded-lg bg-zinc-800/50 p-2 ring-1 ring-white/10 transition-transform duration-300 group-hover:scale-110 group-hover:bg-blue-500/20 group-hover:ring-blue-500/50">
              <Icon className="h-5 w-5 text-zinc-300 transition-colors group-hover:text-blue-400" />
            </div>
            {feature.badge && (
              <span className="rounded-full bg-blue-500/10 px-2 py-0.5 text-xs font-medium text-blue-400 ring-1 ring-blue-500/20">
                {feature.badge}
              </span>
            )}
          </div>
 
          <h3 className="mb-2 text-lg font-semibold text-white transition-colors group-hover:text-blue-100">
            {feature.title}
          </h3>
          <p className="mb-6 flex-grow text-sm leading-relaxed text-zinc-400">
            {feature.description}
          </p>
 
          {feature.cta && (
            <div className="flex items-center text-xs font-medium text-zinc-500 transition-colors group-hover:text-blue-400">
              {feature.cta}
              <ArrowRight className="ml-1 h-3 w-3 transition-transform group-hover:translate-x-1" />
            </div>
          )}
        </div>
      </div>
    </motion.div>
  );
}
 
export function FeatureGrid4Col({
  badge,
  headline,
  description,
  features,
  className,
}: FeatureGrid4ColProps) {
  return (
    <section
      className={cn(
        "relative overflow-hidden bg-black py-24 sm:py-32",
        className,
      )}
    >
      {/* Background Pattern */}
      <div className="absolute inset-0 -z-10 h-full w-full bg-[linear-gradient(to_right,#8080800a_1px,transparent_1px),linear-gradient(to_bottom,#8080800a_1px,transparent_1px)] bg-[size:24px_24px]" />
      <div className="absolute left-0 right-0 top-0 -z-10 m-auto h-[310px] w-[310px] rounded-full bg-blue-500/20 opacity-20 blur-[100px]" />
 
      <div className="container mx-auto px-4 md:px-6">
        <div className="mx-auto mb-16 max-w-3xl text-center">
          {badge && (
            <motion.div
              initial={{ opacity: 0, y: 20 }}
              whileInView={{ opacity: 1, y: 0 }}
              viewport={{ once: true }}
              transition={{ duration: 0.5 }}
              className="mb-4 inline-flex items-center rounded-full border border-zinc-800 bg-zinc-900/50 px-3 py-1 text-sm font-medium text-zinc-300 backdrop-blur-md"
            >
              <span className="mr-2 h-1.5 w-1.5 rounded-full bg-blue-500 animate-pulse" />
              {badge}
            </motion.div>
          )}
 
          <motion.h2
            initial={{ opacity: 0, y: 20 }}
            whileInView={{ opacity: 1, y: 0 }}
            viewport={{ once: true }}
            transition={{ duration: 0.5, delay: 0.1 }}
            className="mb-4 text-3xl font-bold tracking-tight text-white sm:text-4xl md:text-5xl"
          >
            {headline}
          </motion.h2>
 
          {description && (
            <motion.p
              initial={{ opacity: 0, y: 20 }}
              whileInView={{ opacity: 1, y: 0 }}
              viewport={{ once: true }}
              transition={{ duration: 0.5, delay: 0.2 }}
              className="mx-auto max-w-2xl text-lg text-zinc-400"
            >
              {description}
            </motion.p>
          )}
        </div>
 
        <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
          {features.map((feature, index) => (
            <FeatureCard key={index} feature={feature} index={index} />
          ))}
        </div>
      </div>
    </section>
  );
}

Update the import paths to match your project setup.

Features

  • Professional design - Clean cards with elegant spacing
  • Gradient icons - Beautiful gradient backgrounds for all icons
  • Optional metrics - Show growth stats (e.g., "+127%")
  • Feature badges - "Popular", "New", "Enterprise" labels
  • Interactive links - "Learn more" links with hover effects
  • Hover animations - Icon scales, card lifts, gradient reveals
  • Bottom CTA card - Professional call-to-action section
  • Responsive grid - 4 columns → 2 columns → 1 column
  • Shadcn components - Built with Card, Badge, Button
  • TypeScript support - Full type safety
  • Production-ready - Copy and paste to use

Usage

Basic Usage

import FeatureGrid4Col from "@/components/ui/feature-grid-4col";
import { Terminal, Database, Cloud } from "lucide-react";
 
export default function FeaturesPage() {
  return (
    <FeatureGrid4Col
      headline="Platform Features"
      features={[
        {
          icon: Terminal,
          title: "Edge Functions",
          description: "Run code at the edge globally.",
        },
        {
          icon: Database,
          title: "Database",
          description: "Serverless storage for your data.",
        },
        // ... more features
      ]}
    />
  );
}

With Badges and CTAs

<FeatureGrid4Col
  badge="New"
  headline="Advanced Capabilities"
  description="Explore our latest features designed for scale."
  features={[
    {
      icon: Cloud,
      title: "Auto-Scaling",
      description: "Scale automatically with traffic.",
      badge: "Beta",
      cta: "Learn more",
      href: "/scaling",
    },
    // ...
  ]}
/>

Props

FeatureGrid4ColProps

PropTypeDefaultDescription
badgestringundefinedOptional badge text above headline
headlinestringRequiredMain section headline
descriptionstringundefinedOptional description below headline
featuresFeature[]RequiredArray of feature objects
classNamestringundefinedOptional class name for the section

Feature Object

PropTypeDescription
iconLucideIconIcon component from lucide-react
titlestringFeature title
descriptionstringFeature description
badgestringOptional small badge on the card
ctastringOptional Call to Action text
hrefstringOptional link URL

TypeScript Interface

import { LucideIcon } from "lucide-react";
 
interface Feature {
  icon: LucideIcon;
  title: string;
  description: string;
  badge?: string;
  href?: string;
  cta?: string;
}
 
interface FeatureGrid4ColProps {
  badge?: string;
  headline: string;
  description?: string;
  features: Feature[];
  className?: string;
}

Customization

import { Card } from "@/components/ui/card";
 
<Card className="rounded-2xl border-2 p-8 hover:shadow-2xl">
  {/* content */}
</Card>;

Hide CTA Section

Simply omit the cta prop:

<FeatureGrid4Col
  headline="Features"
  features={
    [
      /* ... */
    ]
  }
  // No cta prop
/>

Use Cases

Perfect for:

  • Product feature pages
  • SaaS platform capabilities
  • Service offerings
  • Tool comparisons
  • Benefits sections
  • Technology showcases
  • Integration displays
  • API features

Best Practices

  1. Optimal feature count - 8-12 features work best for 4-column layout
  2. Use metrics wisely - Only add metrics where relevant (growth, speed, etc.)
  3. Badge sparingly - Highlight 2-3 key features with badges
  4. Consistent descriptions - Keep similar length (1-2 sentences)
  5. Relevant icons - Choose icons that clearly represent the feature
  6. Test interactions - Ensure all links and CTAs work properly
  7. Mobile optimization - Test on mobile devices