Skip to content

Cta Demo

Book-a-demo CTA: benefits list on the left, bordered form card (work email, company, team size select) on the right with an inline success state.

neo-corporate/section/cta-demo
Open ↗

Source

"use client";

import { useId, useState, type FormEvent } from "react";
import { CheckCircle2 } from "lucide-react";
import { cn } from "@/lib/utils";

export interface CtaDemoProps {
  title?: string;
  description?: string;
  points?: string[];
  onSubmit?: (data: { email: string; company: string; size: string }) => void;
  className?: string;
}

/** Book-a-demo CTA: benefits list on the left, bordered form card (work email, company, team size select) on the right with an inline success state. */
export function CtaDemo({
  title = "See Ledgerly on your own numbers",
  description = "A 30-minute walkthrough with a finance specialist, tailored to your ERP and entities.",
  points = ["Live demo with your invoice volume", "Implementation plan and timeline", "ROI estimate for your team"],
  onSubmit,
  className,
}: CtaDemoProps) {
  const id = useId();
  const [done, setDone] = useState(false);
  const handle = (e: FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    const f = new FormData(e.currentTarget);
    onSubmit?.({ email: String(f.get("email")), company: String(f.get("company")), size: String(f.get("size")) });
    setDone(true);
  };
  const field = "da-focus da-stroke h-11 w-full rounded-da-md bg-da-surface px-3 text-da-surface-fg placeholder:text-da-muted-fg focus:border-da-primary";
  return (
    <section aria-labelledby={`${id}-t`} className={cn("da-section bg-da-surface-2 text-da-fg", className)}>
      <div className="da-container grid items-center gap-10 lg:grid-cols-2">
        <div>
          <h2 id={`${id}-t`} className="font-da-display text-[clamp(2rem,4.5vw,3rem)] leading-[1.1] font-extrabold tracking-da-display text-balance">
            {title}
          </h2>
          <p className="mt-4 text-lg text-da-muted-fg">{description}</p>
          <ul className="mt-6 space-y-3">
            {points.map((p) => (
              <li key={p} className="flex items-center gap-2.5 font-medium">
                <CheckCircle2 aria-hidden className="size-5 text-da-primary" />
                {p}
              </li>
            ))}
          </ul>
        </div>
        <div className="da-stroke rounded-da-lg bg-da-surface p-6 text-da-surface-fg shadow-da-lg sm:p-8">
          {done ? (
            <div role="status" className="py-10 text-center">
              <CheckCircle2 aria-hidden className="mx-auto size-10 text-da-success" />
              <p className="mt-4 font-da-display text-xl font-bold">Request received</p>
              <p className="mt-1 text-da-muted-fg">A specialist will email you within one business day.</p>
            </div>
          ) : (
            <form onSubmit={handle} className="grid gap-4">
              <div>
                <label htmlFor={`${id}-e`} className="mb-1.5 block text-sm font-medium">
                  Work email
                </label>
                <input id={`${id}-e`} name="email" type="email" required autoComplete="email" placeholder="you@company.com" className={field} />
              </div>
              <div className="grid gap-4 sm:grid-cols-2">
                <div>
                  <label htmlFor={`${id}-c`} className="mb-1.5 block text-sm font-medium">
                    Company
                  </label>
                  <input id={`${id}-c`} name="company" required autoComplete="organization" placeholder="Northwind" className={field} />
                </div>
                <div>
                  <label htmlFor={`${id}-s`} className="mb-1.5 block text-sm font-medium">
                    Finance team size
                  </label>
                  <select id={`${id}-s`} name="size" defaultValue="2-10" className={field}>
                    <option value="1">Just me</option>
                    <option value="2-10">2–10</option>
                    <option value="11-50">11–50</option>
                    <option value="50+">50+</option>
                  </select>
                </div>
              </div>
              <button
                type="submit"
                className="da-focus da-transition mt-2 h-11 rounded-da-md bg-da-primary font-semibold text-da-primary-fg hover:bg-da-primary/90"
              >
                Book a demo
              </button>
              <p className="text-center text-xs text-da-muted-fg">By submitting you agree to our privacy policy.</p>
            </form>
          )}
        </div>
      </div>
    </section>
  );
}

export default CtaDemo;

modules/neo-corporate/section/cta-demo/index.tsx

Props

PropTypeDefaultDescription
titlestring—Heading.
descriptionstring—Supporting text.
pointsstring[]—Points.
onSubmit(data: { email: string; company: string; size: string }) => void—Callback.
classNamestring—Extra classes on the root.

Other cta variants in Neo Corporate

CTA in other art directions

CTA Banner

Full-bleed yellow slab with a giant uppercase headline and an inline email capture form (pending + success states), ruled pattern in the corner.

BrutalistCTA

CTA Countdown

Limited-offer CTA in an ink slab: uppercase offer headline, yellow claim button, dashed promo code, and a four-cell live countdown (days/hours/min/sec) with the first cell in yellow.

BrutalistCTA

CTA Split

Two-audience CTA: a big headline over two fully clickable cards (yellow for engineers, blue for product teams) with audience label, title, pitch and a button chip; cards slam into their shadow on hover.

BrutalistCTA

CTA Sticker

Full-bleed pink CTA with a giant centered uppercase headline, an oversized ink button that slams into its shadow on hover, and a yellow circular text-path sticker ticking around in steps.

BrutalistCTA

Cta App

App download CTA in a glass panel: headline, ink store buttons and rating on the left; an HTML phone mock-up recording an in-person meeting (mic orb, waveform, AI chip) rising from the bottom on the right.

GlassCTA

Cta Gradient

Bold full-gradient CTA card with a masked grid overlay and top glow, white primary button, translucent secondary button and three frosted stat chips.

GlassCTA

CTA Orb

Large frosted panel with a slowly spinning, heavily blurred conic-gradient orb glowing through the glass, centered headline, ink + frosted CTAs and a reassurance line.

GlassCTA

Cta Waitlist

Frosted CTA panel haloed by a blurred gradient ring: headline, copy, pill email form with gradient button (success state) and three check perks.

GlassCTA

Cta Banner

Compact inverted ink banner on a single row: title and one-liner on the left, solid and outline actions on the right, with a faint grid fading in from the right edge.

MinimalCTA

CTA Glow

Closing call-to-action card: centered headline and copy, ink button with keyboard hint, ghost secondary link, an indigo glow rising from the bottom edge and a gradient hairline on top.

MinimalCTA

Cta Newsletter

Centered email capture card with an indigo hairline on top: headline, copy, email field and ink button, with client validation plus pending, success and error states.

MinimalCTA

Cta Split

Wide two-column CTA card: headline, copy and two buttons on the left; a tinted panel on the right with a numbered ‘first 10 minutes’ onboarding checklist and time estimates.

MinimalCTA

Cta Contact

Studio-style contact CTA: mono label, headline, the email address set huge as a link, and a row of contact channels (studio, press, careers) in mono under a hairline.

Mono CleanCTA

Cta Email

Underline-input signup: large headline, then an email field drawn as a single bottom rule with an inline “Get started →” button; confirmation replaces the form.

Mono CleanCTA

Cta Giant

Full-width CTA as a giant link: the whole headline is the link, an arrow slides in on hover and an ink underline wipes across; a mono note sits below.

Mono CleanCTA

Cta Split

Two-door CTA: the section is split into two equal halves (white | ink) with a mono label and a large title each; hovering a half inverts it and nudges the arrow.

Mono CleanCTA

Cta Blob

Closing CTA inside a large sage organic blob (SVG shape scaled to the content) with a clay pebble and two leaves around it; serif headline and cream pill buttons.

Organic SoftCTA

Cta Journal

Newsletter CTA styled like a paper journal: clay-tinted card with serif title, recent issue list with mono numbers, and a rounded email + button form with a warm thank-you state.

Organic SoftCTA

Cta Pledge

Interactive pledge CTA: pick the commitments your team is ready for (round check cards), a counter of companies who pledged, and a CTA that reflects how many you chose.

Organic SoftCTA

Cta Wave

Full-width sage band with soft wavy top and bottom edges (SVG), centered serif headline with an italic word, and two pill buttons; flows naturally between cream sections.

Organic SoftCTA

Cta App

App-download CTA on a peach block: headline and ink store buttons on the left, a flat white phone mock-up with a “Today” checklist (mint done items) rising from the bottom on the right.

Soft FlatCTA

Cta Block

Big periwinkle rounded block with pastel circles peeking from the corners, a centered white headline and two pill buttons (solid white and translucent).

Soft FlatCTA

Cta Illustrated

Split CTA in a white rounded card: headline, ink pill button and note on the left; a composition of pastel circle, pill, rotated square and a ✅ tile on the right.

Soft FlatCTA

Cta Newsletter

Newsletter CTA on a mint block: a flat envelope made of shapes with a notification badge, headline, pill email form and a cheerful success state.

Soft FlatCTA