Logo Cloud Grid

A grid layout showcasing various logos for social proof.

Preview

Code

Code

app/page.tsx

1import LogoCloud from "@/sections/logo-cloud"; 2 3const Home = () => { 4 return ( 5 <div className=" w-full h-screen container mx-auto flex items-center justify-center"> 6 <LogoCloud /> 7 </div> 8 ); 9} 10 11export default Home;

Installation

Initialized a project and installed the necessary dependencies to use this component.

1. Initialize a new Next.js project:

Code
npx create-next-app@latest my-app

2. Install Framer Motion

Code
npm install framer-motion --save

Add Logo Cloud Grid Section

Code

src/sections/logo-cloud.tsx

1"use client" 2 3import { Marquee } from "@/components/marquee"; 4import { logoClouds, logoCloudsMobile } from "@/constants"; 5import { ChevronRight } from "lucide-react"; 6import Image from "next/image"; 7import Link from "next/link"; 8import { motion } from "framer-motion"; 9 10interface LogoCloudProps { 11 isTransparent?: boolean; 12} 13 14const LogoCloud = ({ isTransparent = false }: LogoCloudProps) => { 15 return ( 16 <section className=" w-full py-12 z-20 relative"> 17 <div className=" container hidden md:block mx-auto w-full"> 18 <div className="max-w-4xl mx-auto grid md:grid-cols-4 w-full gap-y-7 px-12 py-6 relative group"> 19 <div className={`absolute inset-0 ${isTransparent ? 'bg-transparent backdrop-blur-sm' : 'bg-black/60 backdrop-blur-xs'} z-20 flex items-center justify-center opacity-0 group-hover:opacity-100 transition-all duration-300 ease-in-out`}> 20 <Link href="/showcase"> 21 <span className="flex text-white hover:text-white/70 items-center gap-1 text-[15px] transform translate-y-4 group-hover:translate-y-0 transition-transform duration-500 ease-in-out"> 22 <p>Companies using Astrae</p> 23 <ChevronRight className=" size-5" /> 24 </span> 25 </Link> 26 </div> 27 {logoClouds.map((logo, index) => ( 28 <motion.div 29 key={index} 30 className="relative h-12 w-[180px]" 31 initial={{ opacity: 0, y: 20 }} 32 whileInView={{ opacity: 1, y: 0 }} 33 transition={{ 34 duration: 0.5, 35 delay: index * 0.1, 36 ease: "easeOut" 37 }} 38 viewport={{ once: true, amount: 0.3 }} 39 > 40 <Image fill src={logo.image} alt={logo.name} className="object-contain" /> 41 </motion.div> 42 ))} 43 </div> 44 </div> 45 <div className=" w-full relative md:hidden"> 46 <div className="absolute top-0 bottom-0 left-0 w-[20%] z-[1] bg-gradient-to-r from-black to-transparent" /> 47 <div className="absolute top-0 bottom-0 right-0 w-[20%] z-[1] bg-gradient-to-l from-black to-transparent" /> 48 <Marquee className="[--gap:-0rem]"> 49 <div className="flex items-center"> 50 {logoCloudsMobile.map((logo, index) => ( 51 <div key={index} className="relative h-9 w-[148px]"> 52 <Image fill src={logo.image} alt={logo.name} className="object-contain" /> 53 </div> 54 ))} 55 </div> 56 </Marquee> 57 </div> 58 </section> 59 ); 60} 61 62export default LogoCloud;

Add Marquee Component

Code

src/components/marquee.tsx

1import { cn } from "@/lib/utils"; 2import { ComponentPropsWithoutRef } from "react"; 3 4interface MarqueeProps extends ComponentPropsWithoutRef<"div"> { 5 /** 6 * Optional CSS class name to apply custom styles 7 */ 8 className?: string; 9 /** 10 * Whether to reverse the animation direction 11 * @default false 12 */ 13 reverse?: boolean; 14 /** 15 * Whether to pause the animation on hover 16 * @default false 17 */ 18 pauseOnHover?: boolean; 19 /** 20 * Content to be displayed in the marquee 21 */ 22 children: React.ReactNode; 23 /** 24 * Whether to animate vertically instead of horizontally 25 * @default false 26 */ 27 vertical?: boolean; 28 /** 29 * Number of times to repeat the content 30 * @default 4 31 */ 32 repeat?: number; 33} 34 35export function Marquee({ 36 className, 37 reverse = false, 38 pauseOnHover = false, 39 children, 40 vertical = false, 41 repeat = 4, 42 ...props 43}: MarqueeProps) { 44 return ( 45 <div 46 {...props} 47 className={cn( 48 "group flex overflow-hidden z-20 p-2 [--duration:40s] [--gap:1rem] [gap:var(--gap)]", 49 { 50 "flex-row": !vertical, 51 "flex-col": vertical, 52 }, 53 className, 54 )} 55 > 56 {Array(repeat) 57 .fill(0) 58 .map((_, i) => ( 59 <div 60 key={i} 61 className={cn("flex [gap:var(--gap)]", { 62 "animate-marquee flex-row": !vertical, 63 "animate-marquee-vertical flex-col": vertical, 64 "group-hover:[animation-play-state:paused]": pauseOnHover, 65 "[animation-direction:reverse]": reverse, 66 })} 67 > 68 {children} 69 </div> 70 ))} 71 </div> 72 ); 73}

Add Constants

Code

src/constants/index.ts

1export const logoClouds = [ 2 { 3 name: "Linear", 4 image: "/assets/company-logo-1.png", 5 }, 6 { 7 name: "Splunk", 8 image: "/assets/company-logo-2.png", 9 }, 10 { 11 name: "Dropbox", 12 image: "/assets/company-logo-3.png", 13 }, 14 { 15 name: "Hopin", 16 image: "/assets/company-logo-4.png", 17 }, 18 { 19 name: "Zapier", 20 image: "/assets/company-logo-5.png", 21 }, 22 { 23 name: "Attentive", 24 image: "/assets/company-logo-6.png", 25 }, 26 { 27 name: "Rippling", 28 image: "/assets/company-logo-7.png", 29 }, 30 { 31 name: "Descript", 32 image: "/assets/company-logo-8.png", 33 }, 34]; 35 36export const logoCloudsMobile = [ 37 { 38 name: "Linear", 39 image: "/assets/c-logo-1.png", 40 }, 41 { 42 name: "Splunk", 43 image: "/assets/c-logo-2.png", 44 }, 45 { 46 name: "Dropbox", 47 image: "/assets/c-logo-3.png", 48 }, 49 { 50 name: "Hopin", 51 image: "/assets/c-logo-4.png", 52 }, 53 { 54 name: "Zapier", 55 image: "/assets/c-logo-5.png", 56 }, 57 { 58 name: "Attentive", 59 image: "/assets/c-logo-6.png", 60 }, 61 { 62 name: "Rippling", 63 image: "/assets/c-logo-7.png", 64 }, 65 { 66 name: "Descript", 67 image: "/assets/c-logo-8.png", 68 }, 69];

Become an Astrae
Affiliate Today

Make referrals, and bring in clients. Keep 50% of your earnings paid out weekly.

Description