/// Cards
DualCTA
The split page-closer — two hover-inverting CTA halves (mono eyebrow + headline + outbound arrow) in one bordered surface, divided by a hairline.
import { DualCTA } from "@protocore/pds";Basics
Pass two columns, each with an eyebrow and title. When a column has an href, the whole half renders as an <a> (with optional target/rel) and shows the outbound ↗︎. Each half inverts on hover.
Button halves
Without an href, a half renders as a <div> and fires onClick — use it for in-app actions rather than navigation. Set arrow={false} to drop the outbound indicator when the action isn't a link.
When to use it
DualCTA is a page-level closer: the recurring "talk to us / start building" split that sits above the footer. It's a *layout* component for exactly two balanced choices, not a general button group. For a *toolbar* of several actions use ButtonGroup; for a *single* call to action a plain Button is right. For a *tinted note* with an action, use Callout. Reserve DualCTA for the two-way fork at the end of a page or section — one path per half, no more than two halves.
Usage
Do
- Give each half a parallel `eyebrow` + `title` so the two choices read as peers.
- Use `href` for navigation halves and `onClick` for in-app halves.
- Keep it to two columns — the layout is a balanced split, not an n-up grid.
- Drop the arrow (`arrow={false}`) on non-link halves so the `↗︎` doesn't imply navigation.
Don't
- Don't pass three or more columns; the halves stop being balanced.
- Don't mix a giant headline in one half with a terse one in the other — keep them symmetric.
- Don't use DualCTA as a generic button container; that's ButtonGroup.
- Don't set `target="_blank"` without a matching `rel` for external links.
Accessibility
| Keys | Action |
|---|---|
| Tab | Moves focus to each CTA half in order. |
| Enter | Activates the focused half — follows the link, or fires onClick. |
| Space | Activates a link half (native anchor behavior). |
- Halves with an `href` are real anchors and are keyboard-focusable by default. Halves that only take `onClick` render as a `<div>` — add `role="button"` and `tabIndex={0}` via the column's props if the action must be keyboard-reachable, or prefer an `href` where one exists.
- The `↗︎` arrow is `aria-hidden`; the accessible name comes from the `title` (and `eyebrow`) text.
- The inversion on hover is mirrored by `:focus-visible`, so keyboard users see the same active-state feedback.
DualCTA props
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | — | |
columns * | DualCTAColumn[] | — | The CTA halves — typically two — laid into equal columns. |
style | CSSProperties | — |