# CTA 02 - Video Background CTA

> A high impact call-to-action section with autoplay background video, bold overlay headline, primary button, and rotating ticker text, perfect for luxury brands or real estate to capture attention instantly.

A shadcn/ui block from the [@shadcn-space](https://shadcnspace.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/shadcn-space/cta-02).

- Page, with a live preview: https://shadcn.exchange/r/shadcn-space/cta-02
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/shadcn-space/cta-02-light-2f0fc28572394069.png
- Registry item: https://shadcnspace.com/r/cta-02.json
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://shadcnspace.com/r/cta-02.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `@iconify/react`
- Registry items: `separator`

## Files

### `src/components/shadcn-space/blocks/cta-02/page.tsx`

```tsx
import CTA from "@/components/shadcn-space/blocks/cta-02/cta";

export default function Page() {
    return (
        <main>
            <CTA />
        </main>
    )
}
```

### `src/components/shadcn-space/blocks/cta-02/cta.tsx`

```tsx
import { Marquee } from "@/components/shadcn-space/animations/marquee";
import { Separator } from "@/components/ui/separator";

interface CTAProps {
    marqueeItems?: string[];
}

const defaultMarqueeItems = [
    "Find your dream home with our expert real estate agents!",
    "Browse thousands of listings in prime locations at great prices!",
    "Get a free property valuation—sell your home with confidence!",
    "Secure the best mortgage rates with our trusted loan partners!",
];

const CTA: React.FC<CTAProps> = ({ marqueeItems = defaultMarqueeItems }) => {
    return (
        <section>
            <div className='max-w-7xl mx-auto sm:px-16 px-4 sm:py-20 py-8'>
                <div className="relative rounded-t-2xl overflow-hidden min-h-96 bg-black/30 flex items-center justify-center">
                    <video
                        className="absolute top-0 left-0 -z-10 max-w-fit w-7xl"
                        autoPlay
                        loop
                        muted
                        aria-label="Video background showing luxurious real estate"
                    >
                        <source src="https://videos.pexels.com/video-files/7233782/7233782-hd_1920_1080_25fps.mp4" type="video/mp4" />
                    </video>

                    <div className="h-full w-full py-16 px-10">
                        <div className="flex flex-col items-center gap-8">
                            <h2 className='text-white sm:text-4xl text-3xl max-w-2xl text-center font-medium'>
                                Enter a realm where exquisite design and timeless luxury come together.
                            </h2>
                            <a href="#" className='bg-white dark:bg-black py-3.5 px-6 rounded-full text-primary hover:bg-black dark:hover:bg-white hover:text-white dark:hover:text-black duration-300 font-medium text-sm'>
                                Get In Touch
                            </a>
                        </div>
                    </div>
                </div>
                <div className="w-full py-4 bg-teal-400 rounded-b-2xl overflow-hidden border-t border-black/5">
                    <Marquee className="[--duration:40s] [--gap:1.25rem] p-0" pauseOnHover>
                        {marqueeItems.map((item, index) => (
                            <div key={index} className="flex items-center gap-6">
                                <p className='text-gray-950 whitespace-nowrap text-sm'>
                                    {item}
                                </p>
                                <Separator className="w-8! bg-gray-950" />
                            </div>
                        ))}
                    </Marquee>
                </div>

            </div>
        </section>
    );
};

export default CTA;
```

### `src/components/shadcn-space/animations/marquee.tsx`

```tsx
import { ComponentPropsWithoutRef } from "react";
 
import { cn } from "@/lib/utils";
 
interface MarqueeProps extends ComponentPropsWithoutRef<"div"> {
  className?: string;
  /**
   * Whether to reverse the animation direction
   * @default false
   */
  reverse?: boolean;
  /**
   * Whether to pause the animation on hover
   * @default false
   */
  pauseOnHover?: boolean;
  /**
   * Content to be displayed in the marquee
   */
  children: React.ReactNode;
  /**
   * Whether to animate vertically instead of horizontally
   * @default false
   */
  vertical?: boolean;
  /**
   * Number of times to repeat the content
   * @default 4
   */
  repeat?: number;
}
 
export function Marquee({
  className,
  reverse = false,
  pauseOnHover = false,
  children,
  vertical = false,
  repeat = 4,
  ...props
}: MarqueeProps) {
  return (
    <>
      <style>
        {`
          @keyframes marquee {
            from {
              transform: translateX(0);
            }
            to {
              transform: translateX(calc(-100% - var(--gap)));
            }
          }
 
          @keyframes marquee-vertical {
            from {
              transform: translateY(0);
            }
            to {
              transform: translateY(calc(-100% - var(--gap)));
            }
          }
 
          @keyframes scroll {
            to {
              transform: translate(calc(-50% - 0.5rem));
            }
          }
 
          .animate-marquee {
            animation: marquee var(--duration) linear infinite;
          }
 
          .animate-marquee-vertical {
            animation: marquee-vertical var(--duration) linear infinite;
          }
 
          .animate-reverse {
            animation-direction: reverse !important;
          }
 
          .pause-on-hover:hover .animate-marquee,
          .pause-on-hover:hover .animate-marquee-vertical {
            animation-play-state: paused !important;
          }
 
          .animate-scroll {
            animation: scroll var(--animation-duration, 40s) var(--animation-direction, forwards) linear infinite;
          }
        `}
      </style>
      <div
        {...props}
        className={cn(
          "group flex gap-(--gap) overflow-hidden p-2 [--duration:40s] [--gap:1rem]",
          {
            "flex-row": !vertical,
            "flex-col": vertical,
            "pause-on-hover": pauseOnHover,
          },
          className,
        )}
      >
        {Array(repeat)
          .fill(0)
          .map((_, i) => (
            <div
              key={i}
              className={cn("flex shrink-0 justify-around gap-(--gap)", {
                "animate-marquee flex-row": !vertical,
                "animate-marquee-vertical flex-col": vertical,
                "animate-reverse": reverse,
              })}
            >
              {children}
            </div>
          ))}
      </div>
    </>
  );
}
```
