Docs
Integration Grid

Integration Grid

Showcase your SaaS integrations with a filterable grid. Features category filtering, popular badges, coming soon tags, and hover effects. Perfect for integration pages and landing pages.

20 Integrations

Integrations

Connect with the tools you already use

Popular
Slack logo

Slack

Get notifications and updates directly in your Slack workspace

Communication
Learn more
Popular
Stripe logo

Stripe

Accept payments and manage subscriptions seamlessly

Payments
Learn more
Popular
GitHub logo

GitHub

Sync your repositories and automate workflows

Development
Learn more
Google Drive logo

Google Drive

Store and share files with your team

Storage
Learn more
Popular
Zapier logo

Zapier

Connect with 5,000+ apps through Zapier automation

Automation
Learn more
Salesforce logo

Salesforce

Sync customer data with your CRM

CRM
Learn more
HubSpot logo

HubSpot

Integrate with your marketing and sales platform

CRM
Learn more
Notion logo

Notion

Embed and sync your workspace data

Productivity
Learn more
Figma logo

Figma

Import designs and collaborate with your team

Design
Learn more
Jira logo

Jira

Track issues and manage projects

Development
Learn more
Dropbox logo

Dropbox

Access and share files from Dropbox

Storage
Learn more
Zoom logo

Zoom

Schedule and join video meetings

Communication
Learn more
Mailchimp logo

Mailchimp

Sync contacts and automate email campaigns

Marketing
Learn more
Intercom logo

Intercom

Connect customer conversations and support

Communication
Learn more
Asana logo

Asana

Manage tasks and projects efficiently

Productivity
Learn more
Coming Soon
Airtable logo

Airtable

Build custom workflows with your data

Productivity
Available soon
Coming Soon
Linear logo

Linear

Streamline issue tracking and project management

Development
Available soon
Coming Soon
Discord logo

Discord

Get updates in your Discord server

Communication
Available soon
Shopify logo

Shopify

Sync your e-commerce store data

E-commerce
Learn more
Twilio logo

Twilio

Send SMS and make voice calls

Communication
Learn more

Don't see your tool?

We're always adding new integrations. Let us know what you need.

Request an integration

Installation

Install dependencies

npm install lucide-react

Copy and paste the following code into your project.

"use client";
 
import React, { useState } from "react";
import { Sparkles, ArrowRight, Zap } from "lucide-react";
 
interface Integration {
  id: string;
  name: string;
  description: string;
  logo: string;
  category: string;
  comingSoon?: boolean;
  popular?: boolean;
  href?: string;
}
 
interface IntegrationGridProps {
  title?: string;
  description?: string;
  integrations: Integration[];
  categories?: string[];
  showFilter?: boolean;
  className?: string;
}
 
export function IntegrationGrid({
  title = "Integrations",
  description = "Connect with the tools you already use",
  integrations,
  categories = [],
  showFilter = true,
  className = "",
}: IntegrationGridProps) {
  const [selectedCategory, setSelectedCategory] = useState<string>("all");
 
  const allCategories = categories.length
    ? categories
    : Array.from(new Set(integrations.map((i) => i.category)));
 
  const filteredIntegrations =
    selectedCategory === "all"
      ? integrations
      : integrations.filter((i) => i.category === selectedCategory);
 
  return (
    <section className={`relative w-full overflow-hidden py-24 ${className}`}>
      <div className="absolute inset-0 -z-10 bg-gradient-to-b from-slate-50/50 via-white to-white dark:from-slate-950/20 dark:via-zinc-950 dark:to-zinc-950" />
      <div className="absolute left-1/4 top-0 -z-10 h-96 w-96 rounded-full bg-gradient-to-br from-slate-400/10 to-zinc-400/10 blur-3xl" />
      <div className="absolute bottom-0 right-1/4 -z-10 h-96 w-96 rounded-full bg-gradient-to-br from-zinc-400/10 to-slate-400/10 blur-3xl" />
 
      <div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
        <div className="mb-12 text-center">
          <div className="mb-4 inline-flex items-center gap-2 rounded-full border border-zinc-200 bg-zinc-50 px-4 py-1.5 text-sm font-semibold text-zinc-700 dark:border-zinc-800 dark:bg-zinc-900 dark:text-zinc-300">
            <Zap className="h-4 w-4" />
            {filteredIntegrations.length} Integrations
          </div>
          <h2 className="mb-4 text-4xl font-bold tracking-tight text-zinc-900 dark:text-white sm:text-5xl">
            {title}
          </h2>
          <p className="mx-auto max-w-2xl text-lg text-zinc-600 dark:text-zinc-400">
            {description}
          </p>
        </div>
 
        {showFilter && allCategories.length > 0 && (
          <div className="mb-12 flex flex-wrap justify-center gap-2">
            <button
              onClick={() => setSelectedCategory("all")}
              className={`rounded-lg px-4 py-2 text-sm font-semibold transition-all ${
                selectedCategory === "all"
                  ? "bg-zinc-900 text-white shadow-lg dark:bg-white dark:text-zinc-900"
                  : "bg-white text-zinc-700 hover:bg-zinc-50 dark:bg-zinc-800 dark:text-zinc-300 dark:hover:bg-zinc-700"
              }`}
            >
              All
            </button>
            {allCategories.map((category) => (
              <button
                key={category}
                onClick={() => setSelectedCategory(category)}
                className={`rounded-lg px-4 py-2 text-sm font-semibold transition-all ${
                  selectedCategory === category
                    ? "bg-zinc-900 text-white shadow-lg dark:bg-white dark:text-zinc-900"
                    : "bg-white text-zinc-700 hover:bg-zinc-50 dark:bg-zinc-800 dark:text-zinc-300 dark:hover:bg-zinc-700"
                }`}
              >
                {category}
              </button>
            ))}
          </div>
        )}
 
        <div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
          {filteredIntegrations.map((integration, index) => (
            <div
              key={integration.id}
              className="group relative overflow-hidden rounded-2xl border border-zinc-200/50 bg-white/80 p-6 backdrop-blur-sm transition-all hover:border-zinc-300 hover:shadow-2xl dark:border-zinc-800/50 dark:bg-zinc-900/80 dark:hover:border-zinc-700"
              style={{
                animationDelay: `${index * 50}ms`,
              }}
            >
              <div className="absolute inset-0 -z-10 bg-gradient-to-br from-zinc-500/5 via-slate-500/5 to-transparent opacity-0 transition-opacity duration-500 group-hover:opacity-100" />
              {integration.popular && (
                <div className="absolute right-4 top-4 z-10">
                  <span className="inline-flex items-center gap-1 rounded-full bg-zinc-900 px-2.5 py-1 text-xs font-bold text-white shadow-lg dark:bg-white dark:text-zinc-900">
                    <Sparkles className="h-3 w-3" />
                    Popular
                  </span>
                </div>
              )}
 
              {integration.comingSoon && (
                <div className="absolute right-4 top-4 z-10">
                  <span className="inline-flex items-center rounded-full border border-zinc-300 bg-white/90 px-2.5 py-1 text-xs font-semibold text-zinc-700 backdrop-blur-sm dark:border-zinc-700 dark:bg-zinc-800/90 dark:text-zinc-300">
                    Coming Soon
                  </span>
                </div>
              )}
 
              <div className="relative mb-4">
                <div className="flex h-20 w-20 items-center justify-center rounded-2xl border border-zinc-200/50 bg-gradient-to-br from-white to-zinc-50 p-4 shadow-sm transition-all group-hover:scale-110 group-hover:shadow-lg dark:border-zinc-800/50 dark:from-zinc-900 dark:to-zinc-800">
                  <img
                    src={integration.logo}
                    alt={`${integration.name} logo`}
                    className="h-full w-full object-contain"
                  />
                </div>
                <div className="absolute inset-0 -z-10 rounded-2xl bg-gradient-to-br from-zinc-400/20 to-slate-400/20 opacity-0 blur-xl transition-opacity duration-500 group-hover:opacity-100" />
              </div>
 
              <div className="mb-4">
                <h3 className="mb-2 text-lg font-bold text-zinc-900 dark:text-white">
                  {integration.name}
                </h3>
                <p className="text-sm leading-relaxed text-zinc-600 dark:text-zinc-400">
                  {integration.description}
                </p>
              </div>
 
              <div className="mb-4">
                <span className="inline-block rounded-lg border border-zinc-200 bg-zinc-50 px-3 py-1 text-xs font-medium text-zinc-700 dark:border-zinc-800 dark:bg-zinc-800 dark:text-zinc-300">
                  {integration.category}
                </span>
              </div>
 
              {integration.href && !integration.comingSoon && (
                <a
                  href={integration.href}
                  className="inline-flex items-center gap-2 text-sm font-semibold text-zinc-900 transition-colors hover:text-zinc-600 dark:text-white dark:hover:text-zinc-300"
                >
                  Learn more
                  <ArrowRight className="h-4 w-4 transition-transform group-hover:translate-x-1" />
                </a>
              )}
 
              {integration.comingSoon && (
                <div className="text-sm font-semibold text-zinc-400 dark:text-zinc-600">
                  Available soon
                </div>
              )}
 
              <div className="absolute bottom-0 left-0 h-1 w-full scale-x-0 bg-gradient-to-r from-zinc-600 via-zinc-800 to-zinc-900 transition-transform duration-500 group-hover:scale-x-100 dark:from-zinc-400 dark:via-zinc-300 dark:to-white" />
            </div>
          ))}
        </div>
 
        {filteredIntegrations.length === 0 && (
          <div className="py-12 text-center">
            <p className="text-zinc-600 dark:text-zinc-400">
              No integrations found in this category.
            </p>
          </div>
        )}
 
        <div className="mt-16 rounded-2xl border border-zinc-200 bg-gradient-to-br from-zinc-50 to-slate-50 p-8 text-center dark:border-zinc-800 dark:from-zinc-900 dark:to-zinc-950">
          <h3 className="mb-2 text-xl font-bold text-zinc-900 dark:text-white">
            Don't see your tool?
          </h3>
          <p className="mb-6 text-sm text-zinc-600 dark:text-zinc-400">
            We're always adding new integrations. Let us know what you need.
          </p>
          <a
            href="#"
            className="inline-flex items-center gap-2 rounded-lg bg-zinc-900 px-6 py-3 text-sm font-semibold text-white shadow-lg transition-all hover:bg-zinc-800 hover:shadow-xl dark:bg-white dark:text-zinc-900 dark:hover:bg-zinc-100"
          >
            Request an integration
            <ArrowRight className="h-4 w-4" />
          </a>
        </div>
      </div>
    </section>
  );
}

Features

  • Professional design - Clean monochrome/grayscale theme
  • Category filtering - Filter integrations by category
  • Popular badges - Highlight most-used integrations
  • Coming soon tags - Show upcoming integrations
  • Hover effects - Subtle glow and scale animations
  • Responsive grid - 1-2-3-4 column layout
  • Logo support - Display integration logos with glow effect
  • External links - Link to integration docs
  • Empty states - Handle no results gracefully
  • CTA section - Request new integrations
  • Dark mode ready - Beautiful in both themes

Usage

Basic Usage

import IntegrationGrid from "@/components/ui/integration-grid";
 
const integrations = [
  {
    id: "1",
    name: "Slack",
    description: "Get notifications in your Slack workspace",
    logo: "/logos/slack.svg",
    category: "Communication",
    popular: true,
    href: "/integrations/slack",
  },
  {
    id: "2",
    name: "Stripe",
    description: "Accept payments seamlessly",
    logo: "/logos/stripe.svg",
    category: "Payments",
    popular: true,
    href: "/integrations/stripe",
  },
];
 
export default function Page() {
  return <IntegrationGrid integrations={integrations} />;
}

With Category Filter

<IntegrationGrid
  title="Integrations"
  description="Connect with the tools you already use"
  integrations={integrations}
  categories={["Communication", "Payments", "Development", "CRM"]}
  showFilter={true}
/>

Coming Soon Integrations

const integrations = [
  {
    id: "1",
    name: "Linear",
    description: "Streamline issue tracking",
    logo: "/logos/linear.svg",
    category: "Development",
    comingSoon: true, // Shows "Coming Soon" badge
  },
];

Props

IntegrationGridProps

PropTypeDefaultDescription
integrationsIntegration[]RequiredArray of integrations
titlestring"Integrations"Section title
descriptionstring"Connect with the tools..."Section description
categoriesstring[]Auto-extractedCategory filter options
showFilterbooleantrueShow category filter
classNamestring""Additional CSS classes

Integration

PropTypeRequiredDescription
idstringYesUnique identifier
namestringYesIntegration name
descriptionstringYesShort description
logostringYesLogo URL or path
categorystringYesCategory name
popularbooleanNoShow "Popular" badge
comingSoonbooleanNoShow "Coming Soon" badge
hrefstringNoLink to integration page

TypeScript Interface

interface Integration {
  id: string;
  name: string;
  description: string;
  logo: string;
  category: string;
  comingSoon?: boolean;
  popular?: boolean;
  href?: string;
}
 
interface IntegrationGridProps {
  title?: string;
  description?: string;
  integrations: Integration[];
  categories?: string[];
  showFilter?: boolean;
  className?: string;
}

Use Cases

Perfect for:

  • Integration pages - Dedicated integrations showcase
  • Landing pages - Show ecosystem strength
  • Product pages - Highlight compatibility
  • Marketing pages - Build trust with logos
  • Documentation - Link to integration guides
  • Partner pages - Showcase partnerships
  • Comparison pages - Show more integrations than competitors
  • Pricing pages - Show value through integrations

Common Patterns

Communication Tools

const communicationIntegrations = [
  {
    id: "slack",
    name: "Slack",
    description: "Get notifications in your Slack workspace",
    logo: "/logos/slack.svg",
    category: "Communication",
    popular: true,
    href: "/integrations/slack",
  },
  {
    id: "teams",
    name: "Microsoft Teams",
    description: "Collaborate with your team",
    logo: "/logos/teams.svg",
    category: "Communication",
    href: "/integrations/teams",
  },
  {
    id: "discord",
    name: "Discord",
    description: "Get updates in your Discord server",
    logo: "/logos/discord.svg",
    category: "Communication",
    comingSoon: true,
  },
];

Developer Tools

const devIntegrations = [
  {
    id: "github",
    name: "GitHub",
    description: "Sync repositories and automate workflows",
    logo: "/logos/github.svg",
    category: "Development",
    popular: true,
    href: "/integrations/github",
  },
  {
    id: "gitlab",
    name: "GitLab",
    description: "Integrate with your GitLab projects",
    logo: "/logos/gitlab.svg",
    category: "Development",
    href: "/integrations/gitlab",
  },
  {
    id: "jira",
    name: "Jira",
    description: "Track issues and manage projects",
    logo: "/logos/jira.svg",
    category: "Development",
    href: "/integrations/jira",
  },
];

Payment Processors

const paymentIntegrations = [
  {
    id: "stripe",
    name: "Stripe",
    description: "Accept payments and manage subscriptions",
    logo: "/logos/stripe.svg",
    category: "Payments",
    popular: true,
    href: "/integrations/stripe",
  },
  {
    id: "paypal",
    name: "PayPal",
    description: "Process payments with PayPal",
    logo: "/logos/paypal.svg",
    category: "Payments",
    href: "/integrations/paypal",
  },
];

Customization

Change Grid Columns

{/* 3 columns max */}
<div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
 
{/* 5 columns max */}
<div className="grid gap-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5">
 
{/* 6 columns max */}
<div className="grid gap-4 sm:grid-cols-3 lg:grid-cols-4 xl:grid-cols-6">

Add Color Accents

{
  /* Add colored filter buttons */
}
<button
  className={`rounded-lg px-4 py-2 text-sm font-semibold transition-all ${
    selectedCategory === "all"
      ? "bg-gradient-to-r from-blue-600 to-cyan-600 text-white shadow-lg"
      : "bg-white text-zinc-700 hover:bg-zinc-50"
  }`}
>
  All
</button>;
 
{
  /* Add colored bottom border */
}
<div className="absolute bottom-0 left-0 h-1 w-full scale-x-0 bg-gradient-to-r from-blue-500 via-cyan-500 to-teal-500 transition-transform duration-500 group-hover:scale-x-100" />;

Custom Badge Colors

{
  /* Popular badge - default is black/white */
}
<span className="bg-zinc-900 text-white dark:bg-white dark:text-zinc-900">
  Popular
</span>;
 
{
  /* Change to colored badge */
}
<span className="bg-gradient-to-r from-blue-600 to-cyan-600 text-white">
  Popular
</span>;
 
{
  /* Coming soon badge */
}
<span className="border border-zinc-300 bg-white/90 text-zinc-700 dark:border-zinc-700 dark:bg-zinc-800/90 dark:text-zinc-300">
  Coming Soon
</span>;
const [searchQuery, setSearchQuery] = useState("");
 
const filteredIntegrations = integrations.filter((integration) =>
  integration.name.toLowerCase().includes(searchQuery.toLowerCase())
);
 
<input
  type="text"
  placeholder="Search integrations..."
  value={searchQuery}
  onChange={(e) => setSearchQuery(e.target.value)}
  className="mb-8 w-full rounded-lg border px-4 py-2"
/>;

Add Integration Count

<div className="mb-8 text-center">
  <p className="text-sm text-zinc-600 dark:text-zinc-400">
    {filteredIntegrations.length} integrations available
  </p>
</div>

Integration

With CMS

async function getIntegrations() {
  const response = await fetch("/api/integrations");
  const data = await response.json();
 
  return data.integrations.map((item) => ({
    id: item.id,
    name: item.name,
    description: item.description,
    logo: item.logoUrl,
    category: item.category,
    popular: item.isPopular,
    comingSoon: item.status === "coming_soon",
    href: `/integrations/${item.slug}`,
  }));
}

With Analytics

const trackIntegrationClick = (integrationName: string) => {
  // Track with your analytics tool
  analytics.track("Integration Clicked", {
    integration: integrationName,
    category: selectedCategory,
  });
};
 
<a
  href={integration.href}
  onClick={() => trackIntegrationClick(integration.name)}
>
  Learn more
</a>;

Dynamic Categories

// Auto-extract categories from integrations
const categories = Array.from(
  new Set(integrations.map((i) => i.category))
).sort();
 
// Count integrations per category
const categoryCounts = categories.reduce((acc, cat) => {
  acc[cat] = integrations.filter((i) => i.category === cat).length;
  return acc;
}, {});

Advanced Features

With Tabs Instead of Filters

<Tabs defaultValue="all">
  <TabsList>
    <TabsTrigger value="all">All</TabsTrigger>
    <TabsTrigger value="communication">Communication</TabsTrigger>
    <TabsTrigger value="development">Development</TabsTrigger>
  </TabsList>
  <TabsContent value="all">{/* All integrations */}</TabsContent>
</Tabs>

With Modal Details

const [selectedIntegration, setSelectedIntegration] = useState(null);
 
<Dialog
  open={!!selectedIntegration}
  onOpenChange={() => setSelectedIntegration(null)}
>
  <DialogContent>
    <DialogTitle>{selectedIntegration?.name}</DialogTitle>
    <DialogDescription>{selectedIntegration?.description}</DialogDescription>
    {/* More details */}
  </DialogContent>
</Dialog>;

With Sorting

const [sortBy, setSortBy] = useState("popular");
 
const sortedIntegrations = [...integrations].sort((a, b) => {
  if (sortBy === "popular") return b.popular ? 1 : -1;
  if (sortBy === "name") return a.name.localeCompare(b.name);
  return 0;
});