CategoriesAllHeroNavigationFooterCall-to-ActionsFeature SectionsTestimonialsPricingContactGalleryStatsFAQServicesNewsletterAuthMiscellaneousButtons
All Components3D Cube InteractionBorder Logo GridCountdownFlip ButtonExpandable FAQsFlow ButtonGlow ButtonGrayscale CarouselInertia Zoom ParallaxLogo Cloud GridMobile Drawer NavigationPixel PreloaderProject GalleryRing ButtonShowcase CarouselSlide PreloaderSliding Stairs PreloaderStormtrooper FAQText Gradient OpacityThreads ButtonTilt HeadlineUltra Preloader
Code
app/page.tsx
1"use client"
2
3import ShowcaseCard from "@/components/showcase-card";
4import {
5  Carousel,
6  CarouselContent,
7  CarouselItem,
8  CarouselNext,
9  CarouselPrevious
10} from "@/components/ui/carousel";
11import Autoplay from "embla-carousel-autoplay";
12
13const ShowcasePage = () => {
14  return (
15    <section className=" w-full py-20 flex items-center justify-center bg-black h-screen">
16      <div className=" w-full relative group">
17        <div className="absolute top-0 bottom-0 left-0 w-[2%] md:w-[20%] z-[1] bg-gradient-to-r from-black to-transparent" />
18        <div className="absolute top-0 bottom-0 right-0 w-[2%] md:w-[20%] z-[1] bg-gradient-to-l from-black to-transparent" />
19
20        <Carousel
21          plugins={[
22            Autoplay({
23              delay: 5000,
24            }),
25          ]}
26          opts={{
27            align: "center",
28            loop: true,
29          }}
30          className="w-full"
31        >
32          <CarouselContent className="px-3 md:px-0">
33            <CarouselItem className=" basis-[90%] md:basis-1/4">
34              <ShowcaseCard color="#FB3F00" icon="/assets/showcase-icon-1.png" image="/assets/showcase-1.png" video="/videos/showcase-1.mp4" title="Lovi" link="www.lovi.com" />
35            </CarouselItem>
36            <CarouselItem className=" basis-[90%] md:basis-1/4">
37              <ShowcaseCard color="#1500FF" icon="/assets/showcase-icon-2.png" image="/assets/showcase-2.png" video="/videos/showcase-2.mp4" title="Lovi" link="www.lovi.com" />
38            </CarouselItem>
39            <CarouselItem className=" basis-[90%] md:basis-1/4">
40              <ShowcaseCard color="#85C25D" icon="/assets/showcase-icon-3.png" image="/assets/showcase-3.png" video="/videos/showcase-3.mp4" title="Lovi" link="www.lovi.com" />
41            </CarouselItem>
42            <CarouselItem className=" basis-[90%] md:basis-1/4">
43              <ShowcaseCard color="#FF8E1C" icon="/assets/showcase-icon-2.png" image="/assets/showcase-4.png" title="Lovi" link="www.lovi.com" />
44            </CarouselItem>
45            <CarouselItem className=" basis-[90%] md:basis-1/4">
46              <ShowcaseCard color="#4A4A2F" icon="/assets/showcase-icon-1.png" image="/assets/showcase-5.png" title="Lovi" link="www.lovi.com" />
47            </CarouselItem>
48          </CarouselContent>
49          <div className=" opacity-0 group-hover:opacity-100 group-hover:pointer-events-auto transition-opacity duration-200 ease-in pointer-events-none">
50            <CarouselPrevious />
51
52            <CarouselNext />
53          </div>
54        </Carousel>
55      </div>
56    </section>
57  );
58}
59
60export default ShowcasePage;Installation
Initialized a project and installed the necessary dependencies to use this component.
1. Initialize a new Next.js project:
npx create-next-app@latest my-app2. Install Shadcn UI
npx shadcn@latest init3. Install Shadcn Components
npx shadcn@latest add carousel button4. Install Embla Carousel Autoplay
npm install embla-carousel-autoplay --saveAdd Showcase Card Component
src/components/showcase-card.tsx
1import Image from "next/image";
2import Link from "next/link";
3
4const ShowcaseCard = ({
5    title,
6    image,
7    link,
8    video,
9    icon,
10    color
11}: {
12    title: string;
13    video?: string;
14    image: string;
15    link: string;
16    icon: string;
17    color: string;
18}) => {
19    return (
20        <div className=" w-full group/card">
21            {video ? (
22                <div style={{ backgroundColor: color }} className=" rounded-xl w-full p-2.5 md:p-4 relative">
23                    <Link rel="" target="_blank" href={link}>
24                        <div className="absolute hidden rounded-lg group-hover/card:block inset-0 z-20 hover:block cursor-pointer opacity-40" style={{ backgroundColor: color }} />
25                    </Link>
26                    <video
27                        className="w-full h-auto aspect-square rounded-lg"
28                        playsInline
29                        autoPlay
30                        loop
31                        muted
32                        poster={image}
33                    >
34                        <source src={video} type="video/mp4" />
35                        Your browser does not support the video tag.
36                    </video>
37                </div>
38            ) : (
39                <div className=" w-full relative h-auto aspect-square">
40                    <Link rel="" target="_blank" href={link}>
41                        <div className="absolute hidden rounded-lg group-hover/card:block inset-0 z-20 hover:block cursor-pointer opacity-40" style={{ backgroundColor: color }} />
42                    </Link>
43                    <Image
44                        src={image}
45                        alt={title}
46                        fill
47                        className="object-cover rounded-lg"
48                    />
49                </div>
50            )}
51            <div className="flex items-center gap-4 mt-4">
52                <Image width={40} height={40} src={icon} className=" object-cover border rounded-full" alt={title} />
53                <div className="flex flex-col items-start text-white">
54                    <p>{link}</p>
55                    <p>{title}</p>
56                </div>
57            </div>
58        </div>
59    );
60}
61
62export default ShowcaseCard;Update Carousel Component
src/components/ui/carousel.tsx
1"use client"
2
3import useEmblaCarousel, {
4  type UseEmblaCarouselType,
5} from "embla-carousel-react"
6import { ChevronLeft, ChevronRight } from "lucide-react"
7import * as React from "react"
8
9import { Button } from "@/components/ui/button"
10import { cn } from "@/lib/utils"
11
12type CarouselApi = UseEmblaCarouselType[1]
13type UseCarouselParameters = Parameters<typeof useEmblaCarousel>
14type CarouselOptions = UseCarouselParameters[0]
15type CarouselPlugin = UseCarouselParameters[1]
16
17type CarouselProps = {
18  opts?: CarouselOptions
19  plugins?: CarouselPlugin
20  orientation?: "horizontal" | "vertical"
21  setApi?: (api: CarouselApi) => void
22}
23
24type CarouselContextProps = {
25  carouselRef: ReturnType<typeof useEmblaCarousel>[0]
26  api: ReturnType<typeof useEmblaCarousel>[1]
27  scrollPrev: () => void
28  scrollNext: () => void
29  canScrollPrev: boolean
30  canScrollNext: boolean
31} & CarouselProps
32
33const CarouselContext = React.createContext<CarouselContextProps | null>(null)
34
35function useCarousel() {
36  const context = React.useContext(CarouselContext)
37
38  if (!context) {
39    throw new Error("useCarousel must be used within a <Carousel />")
40  }
41
42  return context
43}
44
45function Carousel({
46  orientation = "horizontal",
47  opts,
48  setApi,
49  plugins,
50  className,
51  children,
52  ...props
53}: React.ComponentProps<"div"> & CarouselProps) {
54  const [carouselRef, api] = useEmblaCarousel(
55    {
56      ...opts,
57      axis: orientation === "horizontal" ? "x" : "y",
58    },
59    plugins
60  )
61  const [canScrollPrev, setCanScrollPrev] = React.useState(false)
62  const [canScrollNext, setCanScrollNext] = React.useState(false)
63
64  const onSelect = React.useCallback((api: CarouselApi) => {
65    if (!api) return
66    setCanScrollPrev(api.canScrollPrev())
67    setCanScrollNext(api.canScrollNext())
68  }, [])
69
70  const scrollPrev = React.useCallback(() => {
71    api?.scrollPrev()
72  }, [api])
73
74  const scrollNext = React.useCallback(() => {
75    api?.scrollNext()
76  }, [api])
77
78  const handleKeyDown = React.useCallback(
79    (event: React.KeyboardEvent<HTMLDivElement>) => {
80      if (event.key === "ArrowLeft") {
81        event.preventDefault()
82        scrollPrev()
83      } else if (event.key === "ArrowRight") {
84        event.preventDefault()
85        scrollNext()
86      }
87    },
88    [scrollPrev, scrollNext]
89  )
90
91  React.useEffect(() => {
92    if (!api || !setApi) return
93    setApi(api)
94  }, [api, setApi])
95
96  React.useEffect(() => {
97    if (!api) return
98    onSelect(api)
99    api.on("reInit", onSelect)
100    api.on("select", onSelect)
101
102    return () => {
103      api?.off("select", onSelect)
104    }
105  }, [api, onSelect])
106
107  return (
108    <CarouselContext.Provider
109      value={{
110        carouselRef,
111        api: api,
112        opts,
113        orientation:
114          orientation || (opts?.axis === "y" ? "vertical" : "horizontal"),
115        scrollPrev,
116        scrollNext,
117        canScrollPrev,
118        canScrollNext,
119      }}
120    >
121      <div
122        onKeyDownCapture={handleKeyDown}
123        className={cn("relative", className)}
124        role="region"
125        aria-roledescription="carousel"
126        data-slot="carousel"
127        {...props}
128      >
129        {children}
130      </div>
131    </CarouselContext.Provider>
132  )
133}
134
135function CarouselContent({ className, ...props }: React.ComponentProps<"div">) {
136  const { carouselRef, orientation } = useCarousel()
137
138  return (
139    <div
140      ref={carouselRef}
141      className="overflow-hidden"
142      data-slot="carousel-content"
143    >
144      <div
145        className={cn(
146          "flex",
147          orientation === "horizontal" ? "-ml-4" : "-mt-4 flex-col",
148          className
149        )}
150        {...props}
151      />
152    </div>
153  )
154}
155
156function CarouselItem({ className, ...props }: React.ComponentProps<"div">) {
157  const { orientation } = useCarousel()
158
159  return (
160    <div
161      role="group"
162      aria-roledescription="slide"
163      data-slot="carousel-item"
164      className={cn(
165        "min-w-0 shrink-0 grow-0 basis-full",
166        orientation === "horizontal" ? "pl-4" : "pt-4",
167        className
168      )}
169      {...props}
170    />
171  )
172}
173
174function CarouselPrevious({
175  className,
176  variant = "outline",
177  size = "icon",
178  ...props
179}: React.ComponentProps<typeof Button>) {
180  const { orientation, scrollPrev, canScrollPrev } = useCarousel()
181
182  return (
183    <Button
184      data-slot="carousel-previous"
185      variant={variant}
186      size={size}
187      className={cn(
188        "absolute h-8 md:h-9 w-8 md:w-9 rounded-full hover:bg-white hover:text-black bg-black/50 backdrop-blur-md text-white border-none z-50",
189        orientation === "horizontal"
190          ? " left-12 md:left-[28rem] top-1/2 -translate-y-[100%]"
191          : "-top-12 left-1/2 -translate-x-1/2 rotate-90",
192        className
193      )}
194      disabled={!canScrollPrev}
195      onClick={scrollPrev}
196      {...props}
197    >
198      <ChevronLeft className=" size-5" />
199      <span className="sr-only">Previous slide</span>
200    </Button>
201  )
202}
203
204function CarouselNext({
205  className,
206  variant = "outline",
207  size = "icon",
208  ...props
209}: React.ComponentProps<typeof Button>) {
210  const { orientation, scrollNext, canScrollNext } = useCarousel()
211
212  return (
213    <Button
214      data-slot="carousel-next"
215      variant={variant}
216      size={size}
217      className={cn(
218        "absolute h-8 md:h-9 w-8 md:w-9 rounded-full hover:bg-white bg-black/50 hover:text-black backdrop-blur-md text-white border-none z-50",
219        orientation === "horizontal"
220          ? " right-12 md:right-[28rem] top-1/2 -translate-y-[100%]"
221          : "-bottom-12 left-1/2 -translate-x-1/2 rotate-90",
222        className
223      )}
224      disabled={!canScrollNext}
225      onClick={scrollNext}
226      {...props}
227    >
228      <ChevronRight className=" size-5" />
229      <span className="sr-only">Next slide</span>
230    </Button>
231  )
232}
233
234export {
235  Carousel,
236  CarouselContent,
237  CarouselItem, CarouselNext, CarouselPrevious, type CarouselApi
238}Add Button Component
src/components/ui/button.tsx
1import * as React from "react"
2import { Slot } from "@radix-ui/react-slot"
3import { cva, type VariantProps } from "class-variance-authority"
4
5import { cn } from "@/lib/utils"
6
7const buttonVariants = cva(
8  "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
9  {
10    variants: {
11      variant: {
12        default:
13          "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
14        destructive:
15          "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
16        outline:
17          "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50",
18        secondary:
19          "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80",
20        ghost:
21          "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50",
22        link: "text-primary underline-offset-4 hover:underline",
23      },
24      size: {
25        default: "h-9 px-4 py-2 has-[>svg]:px-3",
26        sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
27        lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
28        icon: "size-9",
29      },
30    },
31    defaultVariants: {
32      variant: "default",
33      size: "default",
34    },
35  }
36)
37
38function Button({
39  className,
40  variant,
41  size,
42  asChild = false,
43  ...props
44}: React.ComponentProps<"button"> &
45  VariantProps<typeof buttonVariants> & {
46    asChild?: boolean
47  }) {
48  const Comp = asChild ? Slot : "button"
49
50  return (
51    <Comp
52      data-slot="button"
53      className={cn(buttonVariants({ variant, size, className }))}
54      {...props}
55    />
56  )
57}
58
59export { Button, buttonVariants }Add Global Styles
src/app/global.css
1@import "tailwindcss";
2@import "tw-animate-css";
3
4@custom-variant dark (&:is(.dark *));
5
6@theme inline {
7  --color-background: var(--background);
8  --color-foreground: var(--foreground);
9  --font-inter: var(--font-inter);
10  --color-sidebar-ring: var(--sidebar-ring);
11  --color-sidebar-border: var(--sidebar-border);
12  --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
13  --color-sidebar-accent: var(--sidebar-accent);
14  --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
15  --color-sidebar-primary: var(--sidebar-primary);
16  --color-sidebar-foreground: var(--sidebar-foreground);
17  --color-sidebar: var(--sidebar);
18  --color-chart-5: var(--chart-5);
19  --color-chart-4: var(--chart-4);
20  --color-chart-3: var(--chart-3);
21  --color-chart-2: var(--chart-2);
22  --color-chart-1: var(--chart-1);
23  --color-ring: var(--ring);
24  --color-input: var(--input);
25  --color-border: var(--border);
26  --color-destructive: var(--destructive);
27  --color-accent-foreground: var(--accent-foreground);
28  --color-accent: var(--accent);
29  --color-muted-foreground: var(--muted-foreground);
30  --color-muted: var(--muted);
31  --color-secondary-foreground: var(--secondary-foreground);
32  --color-secondary: var(--secondary);
33  --color-primary-foreground: var(--primary-foreground);
34  --color-primary: var(--primary);
35  --color-popover-foreground: var(--popover-foreground);
36  --color-popover: var(--popover);
37  --color-card-foreground: var(--card-foreground);
38  --color-card: var(--card);
39  --radius-sm: calc(var(--radius) - 4px);
40  --radius-md: calc(var(--radius) - 2px);
41  --radius-lg: var(--radius);
42  --radius-xl: calc(var(--radius) + 4px);
43}
44
45:root {
46  --radius: 0.625rem;
47  --background: oklch(1 0 0);
48  --foreground: oklch(0.145 0 0);
49  --card: oklch(1 0 0);
50  --card-foreground: oklch(0.145 0 0);
51  --popover: oklch(1 0 0);
52  --popover-foreground: oklch(0.145 0 0);
53  --primary: oklch(0.205 0 0);
54  --primary-foreground: oklch(0.985 0 0);
55  --secondary: oklch(0.97 0 0);
56  --secondary-foreground: oklch(0.205 0 0);
57  --muted: oklch(0.97 0 0);
58  --muted-foreground: oklch(0.556 0 0);
59  --accent: oklch(0.97 0 0);
60  --accent-foreground: oklch(0.205 0 0);
61  --destructive: oklch(0.577 0.245 27.325);
62  --border: oklch(0.922 0 0);
63  --input: oklch(0.922 0 0);
64  --ring: oklch(0.708 0 0);
65  --chart-1: oklch(0.646 0.222 41.116);
66  --chart-2: oklch(0.6 0.118 184.704);
67  --chart-3: oklch(0.398 0.07 227.392);
68  --chart-4: oklch(0.828 0.189 84.429);
69  --chart-5: oklch(0.769 0.188 70.08);
70  --sidebar: oklch(0.985 0 0);
71  --sidebar-foreground: oklch(0.145 0 0);
72  --sidebar-primary: oklch(0.205 0 0);
73  --sidebar-primary-foreground: oklch(0.985 0 0);
74  --sidebar-accent: oklch(0.97 0 0);
75  --sidebar-accent-foreground: oklch(0.205 0 0);
76  --sidebar-border: oklch(0.922 0 0);
77  --sidebar-ring: oklch(0.708 0 0);
78}
79
80.dark {
81  --background: oklch(0.145 0 0);
82  --foreground: oklch(0.985 0 0);
83  --card: oklch(0.205 0 0);
84  --card-foreground: oklch(0.985 0 0);
85  --popover: oklch(0.205 0 0);
86  --popover-foreground: oklch(0.985 0 0);
87  --primary: oklch(0.922 0 0);
88  --primary-foreground: oklch(0.205 0 0);
89  --secondary: oklch(0.269 0 0);
90  --secondary-foreground: oklch(0.985 0 0);
91  --muted: oklch(0.269 0 0);
92  --muted-foreground: oklch(0.708 0 0);
93  --accent: oklch(0.269 0 0);
94  --accent-foreground: oklch(0.985 0 0);
95  --destructive: oklch(0.704 0.191 22.216);
96  --border: oklch(1 0 0 / 10%);
97  --input: oklch(1 0 0 / 15%);
98  --ring: oklch(0.556 0 0);
99  --chart-1: oklch(0.488 0.243 264.376);
100  --chart-2: oklch(0.696 0.17 162.48);
101  --chart-3: oklch(0.769 0.188 70.08);
102  --chart-4: oklch(0.627 0.265 303.9);
103  --chart-5: oklch(0.645 0.246 16.439);
104  --sidebar: oklch(0.205 0 0);
105  --sidebar-foreground: oklch(0.985 0 0);
106  --sidebar-primary: oklch(0.488 0.243 264.376);
107  --sidebar-primary-foreground: oklch(0.985 0 0);
108  --sidebar-accent: oklch(0.269 0 0);
109  --sidebar-accent-foreground: oklch(0.985 0 0);
110  --sidebar-border: oklch(1 0 0 / 10%);
111  --sidebar-ring: oklch(0.556 0 0);
112}
113
114@layer base {
115  * {
116    @apply border-border outline-ring/50;
117  }
118  body {
119    @apply bg-background text-foreground;
120  }
121}