---
title: CTA
description: Call-to-action banner section
visibility: guest
draft: false
---

# CTA

A call-to-action banner section for landing pages and marketing content.

## Basic Usage

:::preview{title="Default CTA"}
<x-wirekit::cta>
    <x-slot:title>Ready to get started?</x-slot:title>
    <x-slot:description>Join thousands of developers building with WireKit.</x-slot:description>
    <x-slot:actions>
        <x-wirekit::button>Sign Up Free</x-wirekit::button>
    </x-slot:actions>
</x-wirekit::cta>
:::

## Dark Variant

:::preview{title="Dark CTA section"}
<x-wirekit::cta variant="dark">
    <x-slot:title>Start building today.</x-slot:title>
    <x-slot:description>Free and open source.</x-slot:description>
    <x-slot:actions>
        <x-wirekit::button intent="neutral">Get Started</x-wirekit::button>
    </x-slot:actions>
</x-wirekit::cta>
:::

The default `intent="primary"` button uses the theme's accent color, which on the stock light theme resolves to a near-black (`oklch(20.5% 0 0)`) and washes out on the dark CTA's near-black background. Inside `variant="dark"`, prefer `intent="neutral"` (light surface) — the same pattern the `variant="accent"` example below uses to break out of its background color.

## Accent Variant

:::preview{title="Accent CTA"}
<x-wirekit::cta variant="accent">
    <x-slot:title>Try WireKit now.</x-slot:title>
    <x-slot:actions>
        <x-wirekit::button intent="neutral">Install</x-wirekit::button>
    </x-slot:actions>
</x-wirekit::cta>
:::

## Entrance Animation

Wire a viewport-triggered reveal directly on the section without an extra wrapper. The preview below uses a manual-trigger reveal so the docs site's preview-frame replay icon (top-right) re-fires the bounce on demand:

:::preview{title="CTA with replayable bounce reveal"}
<x-wirekit::reveal preset="bounce" trigger="manual" :once="false" duration="slow" x-init="$nextTick(() => window.dispatchEvent(new CustomEvent('wirekit:reveal')))">
    <x-wirekit::cta>
        <x-slot:title>Ready to get started?</x-slot:title>
        <x-slot:description>Hit the replay icon above to bounce me back in.</x-slot:description>
        <x-slot:actions>
            <x-wirekit::button>Sign Up Free</x-wirekit::button>
        </x-slot:actions>
    </x-wirekit::cta>
</x-wirekit::reveal>
:::

For the typical scroll-into-view case, use the `animateIn` prop directly on the CTA — equivalent to wrapping the component in `<x-wirekit::reveal trigger="viewport">` but skips the wrapper element:

```blade
<x-wirekit::cta animateIn="slide-up">
    <x-slot:title>Ready to get started?</x-slot:title>
    <x-slot:actions>
        <x-wirekit::button>Sign Up Free</x-wirekit::button>
    </x-slot:actions>
</x-wirekit::cta>
```

The `animateIn` prop accepts any of the 11 base presets (`fade`, `slide-up`, `slide-down`, `slide-left`, `slide-right`, `scale`, `zoom`, `flip`, `rotate`, `bounce`, `spring`). It is equivalent to wrapping the component in `<x-wirekit::reveal>` but skips the wrapper element. Respects `prefers-reduced-motion: reduce`.

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `variant` | string | `'default'` | Visual variant: `default`, `dark`, `accent` |
| `animateIn` | string\|null | `null` | Entrance-reveal preset (e.g. `'fade'`, `'slide-up'`). Wires reveal semantics inline. |
| `size` | `sm` \| `md` \| `lg` | `md` | Vertical-rhythm tier. Reads `--space-wk-section-{size}` tokens. Mobile viewport (< sm breakpoint) automatically drops one tier so the section never overshoots a small viewport. See [hero docs](hero.md#responsive-considerations) for the full breakpoint table — cta follows the same shape. |
| `scope` | string\|null | `null` | Scoped personalization name |

The three `size` tiers:

The demo below uses `variant="default"` so the size differences are observable; on `variant="accent"` or `variant="dark"` CTAs, use `intent="neutral"` on the button (see "Contrast on accent / dark CTAs" above) — the default `intent="primary"` button shares its background color with the accent / dark CTA surface and visually vanishes.

:::preview{title="CTA size — sm / md / lg" wide}
<x-wirekit::cta size="sm">
    <x-slot:title>Tight CTA</x-slot:title>
    <x-slot:actions>
        <x-wirekit::button>Get started</x-wirekit::button>
    </x-slot:actions>
</x-wirekit::cta>

<x-wirekit::cta size="md">
    <x-slot:title>Balanced CTA</x-slot:title>
    <x-slot:actions>
        <x-wirekit::button>Get started</x-wirekit::button>
    </x-slot:actions>
</x-wirekit::cta>

<x-wirekit::cta size="lg">
    <x-slot:title>Roomy CTA</x-slot:title>
    <x-slot:actions>
        <x-wirekit::button>Get started</x-wirekit::button>
    </x-slot:actions>
</x-wirekit::cta>
:::

## Slots

| Slot | Description |
| --- | --- |
| `title` | CTA heading (h2) |
| `description` | Supporting text |
| `actions` | CTA buttons |

## Keyboard Interaction

This component is a layout wrapper. Keyboard interaction is delegated to its children.

## Pitfalls

- **Don't hardcode `text-white` on the accent variant.** Use `text-[var(--color-wk-accent-fg)]` so the foreground auto-switches with the accent in dark mode (CTA-class WCAG 1.4.3 fix shipped 2026-04-21).

## Design Tokens

| Token | Used for |
| --- | --- |
| `--space-wk-section-md` | Vertical padding |
| `--font-wk-heading-weight` | Title weight |
| `--color-wk-bg-muted` | Default background |
| `--color-wk-bg-inverse` | Dark variant background |
| `--color-wk-accent` | Accent variant background |

## Usage & Conventions

> **Prop conventions** — this component uses one or more of the shared semantic prop names (`intent` / `variant` / `tone` / `surface`). See [Prop naming conventions](/extending/prop-naming-conventions) for the canonical vocabulary, alias matrix, and decision tree.
