Agents (llms.txt)

CTA Banner

Full-width call-to-action card with title, description, and one or two actions.

Ready to ship?

Drop in the primitives, copy the blocks, keep your design system honest.

import { CTABanner } from '@/foundations/blocks/cta-banner';
import { Button } from '@/components/button';

export default function CTABannerPreview() {
  return (
    <CTABanner
      layout="side"
      title="Ready to ship?"
      description="Drop in the primitives, copy the blocks, keep your design system honest."
      action={<Button>Get started</Button>}
      secondaryAction={<Button variant="outline">Talk to us</Button>}
    />
  );
}

export const meta = {
  layout: 'fullscreen',
};

Dependencies

Source Code

import { Container } from '@/components/container';
import { cn } from '@/lib/utils/classnames';

interface CTABannerProps
  extends Omit<React.ComponentPropsWithRef<'section'>, 'title'> {
  title: React.ReactNode;
  description?: React.ReactNode;
  /** Primary action — typically a `<Button>`. */
  action?: React.ReactNode;
  /** Optional secondary action. */
  secondaryAction?: React.ReactNode;
  /** Optional background image URL — applied with cover/center positioning. */
  backgroundImage?: string;
  /** Layout — `'side'` puts copy and CTAs in two columns on lg+. */
  layout?: 'stacked' | 'side';
}

const CTABanner = ({
  ref,
  className,
  title,
  description,
  action,
  secondaryAction,
  backgroundImage,
  layout = 'stacked',
  ...rest
}: CTABannerProps) => (
  <section
    ref={ref}
    className={cn('w-full py-16 md:py-24', className)}
    {...rest}
  >
    <Container>
      <div
        style={
          backgroundImage
            ? {
                backgroundImage: `url(${backgroundImage})`,
                backgroundSize: 'cover',
                backgroundPosition: 'center',
              }
            : undefined
        }
        className={cn(
          'flex flex-col gap-6 bg-background p-8 md:p-12 lg:p-16',
          layout === 'side' && 'lg:flex-row lg:items-center lg:justify-between'
        )}
      >
        <div
          className={cn(
            'flex flex-col gap-3',
            layout === 'side' && 'max-w-2xl'
          )}
        >
          <h2 className="text-balance font-semibold text-3xl md:text-4xl lg:text-5xl">
            {title}
          </h2>
          {description && (
            <p className="text-pretty text-xl md:text-2xl">{description}</p>
          )}
        </div>

        {(action || secondaryAction) && (
          <div className="flex flex-wrap gap-3">
            {action}
            {secondaryAction}
          </div>
        )}
      </div>
    </Container>
  </section>
);

export type { CTABannerProps };
export { CTABanner };

CTABanner is the “got a project? let’s talk.” block — a rounded, bordered card with a heading, description, and one or two action buttons. Supports an optional background image and a side-by-side layout on large viewports.

Anatomy


          <CTABanner
  title="Ready to ship?"
  description="Drop in the primitives, copy the blocks, keep your design system honest."
  action={<Button>Get started</Button>}
  secondaryAction={<Button variant="secondary">Talk to us</Button>}
/>
        

API Reference

Extends the section element.

Prop Default Type
title * - ReactNode
description - ReactNode
action - ReactNode
secondaryAction - ReactNode
backgroundImage - string
layout 'stacked' 'stacked''side'

Examples

Default

Ready to ship?

Drop in the primitives, copy the blocks, keep your design system honest.

import { CTABanner } from '@/foundations/blocks/cta-banner';
import { Button } from '@/components/button';

export default function CTABannerPreview() {
  return (
    <CTABanner
      layout="side"
      title="Ready to ship?"
      description="Drop in the primitives, copy the blocks, keep your design system honest."
      action={<Button>Get started</Button>}
      secondaryAction={<Button variant="outline">Talk to us</Button>}
    />
  );
}

export const meta = {
  layout: 'fullscreen',
};

Previous

Core Values

Next

FAQs