Inverted closing panel on a solid dark surface: an oversized invitation on the left, a paragraph and outline pill CTA on the right, then a ruled row of linked email, phone and studio address.
Inverted closing panel on a solid dark surface: an oversized invitation on the left, a paragraph and an outline pill CTA on the right, then a ruled row of linked email, phone and studio address so the section works as the contact block too.
Upgrade to Pro
Pro blocks install through the shadcn CLI with your license key and ship their full source. Docs and live previews stay open to everyone, so you can read every block's details first.
Swap YOUR_EMAIL and YOUR_KEY for the email and license key on your account. Find your license key on your account page.
Radix flavor
npx shadcn add "https://ui.beste.co/r/cta79?email=YOUR_EMAIL&license_key=YOUR_KEY"Base UI flavor
npx shadcn add "https://ui.beste.co/r-base/cta79?email=YOUR_EMAIL&license_key=YOUR_KEY"This installs the block to components/beste/block/cta79.tsx plus the badge7 eyebrow and button12 pill button it uses.
The installed file exports cta79Demo alongside the block: the exact props behind the preview above. Spread it to get a working contact band in one line.
import { Cta79, cta79Demo } from "@/components/beste/block/cta79";
export default function Page() {
return <Cta79 {...cta79Demo} />;
}Then replace the demo with your own props. Written out, a trimmed setup looks like this:
import { Cta79 } from "@/components/beste/block/cta79";
export default function Page() {
return (
<Cta79
badge={{ label: "Say it plainly" }}
heading="Tell us the thing you would rather not put in a brief."
description="The budget that is smaller than it should be, the deadline someone else agreed to."
button={{ label: "Write to the studio", href: "/contact" }}
details={[
{ title: "Email", value: "studio@example.com", href: "mailto:studio@example.com" },
{ title: "Phone", value: "+31 10 555 0148", href: "tel:+31105550148" },
]}
labels={{ note: "Answered by a person, usually the one who would run your project." }}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
badge | { label: string } | – | Eyebrow label rendered as a Badge7, tinted for the dark surface |
heading | string | – | Oversized invitation on the left |
description | string | – | Supporting paragraph above the CTA |
button | ActionButton | – | Outline pill CTA, rendered as Button12 |
details | ContactDetail[] | [] | Ruled row of linked contact facts |
labels | Cta79Labels | {} | Fixed strings that are not content: the closing note |
className | string | – | Extra classes for the outer <section> |
type ActionButton = {
label: string;
href: string;
};
type ContactDetail = {
title: string;
value: string;
href: string;
};
type Cta79Labels = {
note?: string;
};text-background and text-background/70 tokens rather than adaptive ones: this block is meant to stay inverted in both light and dark themes.border-background/20 instead of the default border token, which is what keeps the hairlines visible against the dark fill without glowing.Button12 is set to tone="outline", which on this surface renders a light pill with a dark seal, the highest-contrast option the component offers.mailto: and tel: hrefs work directly, and the underline is the only affordance since the panel has no room for a second button style.Badge7 eyebrow takes a className override to tint it for the dark surface, which is the supported way to recolour it rather than editing the component.dt/dd inside a dl, so label and value stay associated for assistive technology.cta82
A full-width dark closing band with a light display heading, a paragraph, two actions, and three reassurances sitting under a hairline rule.
cta84
A closing call to action set on a photographic panel with a directional gradient, pairing an eyebrow badge, light heading, and two actions with a live customer quote card.
cta72
A monochrome newsletter CTA band pairing an oversized statement with an inline email-capture form and a reassurance note.