# Sentence Form: Demo Request

> An AI startup's demo request on a dark panel. Each team option brings its own grammar ("for just me", "for a company of 500+") and the tools are a pick-any list. Turn on Fail the next send to see the error path: the form keeps every answer and says so beside the button.

A shadcn/ui block from the [@keyframeui](https://keyframeui.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/keyframeui/sentence-form-agent-demo).

- Page, with a live preview: https://shadcn.exchange/r/keyframeui/sentence-form-agent-demo
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/keyframeui/sentence-form-agent-demo-light-c3ba9ef7b6ca4338.png
- Registry item: https://keyframeui.com/r/sentence-form-agent-demo.json
- Categories: form, input, motion
- Listed: 2026-10-14, source last changed 2026-10-15

## Install

```bash
npx shadcn@latest add https://keyframeui.com/r/sentence-form-agent-demo.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- Registry items: `https://keyframeui.com/r/sentence-form.json`

## Notes from the registry

Live preview, examples and props: https://keyframeui.com/components/sentence-form#sentence-form-agent-demo

## Files

### `registry/demos/sentence-form-agent-demo.tsx`

```tsx
"use client";

import * as React from "react";

import { cn } from "@/lib/utils";
import { SentenceForm, SentenceFormField } from "@/components/ui/sentence-form";

export function SentenceFormAgentDemo() {
  const [failNext, setFailNext] = React.useState(false);

  // Stands in for a real request. With the switch on, the next send fails once.
  const send = () =>
    new Promise<void>((resolve, reject) =>
      setTimeout(() => {
        if (!failNext) return resolve();
        setFailNext(false);
        reject(new Error("Network error"));
      }, 1200),
    );

  return (
    <section className="relative w-full max-w-2xl overflow-hidden rounded-3xl bg-zinc-950 px-6 py-8 text-zinc-100 ring-1 ring-white/10 sm:px-10 sm:py-10">
      <div
        aria-hidden
        className="pointer-events-none absolute -top-40 -right-24 size-96 rounded-full bg-indigo-500/20 blur-3xl"
      />
      <div className="relative flex flex-wrap items-center justify-between gap-3">
        <span className="inline-flex items-center gap-2 text-[13px] font-medium text-zinc-400">
          <span aria-hidden className="size-1.5 rounded-full bg-indigo-400 shadow-[0_0_10px_2px] shadow-indigo-400/60" />
          Book a demo
        </span>
        <label className="inline-flex h-8 cursor-pointer items-center gap-2 rounded-lg px-2.5 text-xs font-medium text-zinc-400 select-none hover:bg-white/5">
          <input
            type="checkbox"
            checked={failNext}
            onChange={(e) => setFailNext(e.target.checked)}
            className="peer sr-only"
          />
          <span
            aria-hidden
            className="relative h-4 w-7 rounded-full bg-zinc-700 transition-colors duration-200 peer-checked:bg-rose-500 peer-focus-visible:ring-2 peer-focus-visible:ring-zinc-500"
          >
            <span
              className={cn(
                "absolute top-0.5 left-0.5 size-3 rounded-full bg-white shadow-sm transition-transform duration-200",
                failNext && "translate-x-3",
              )}
            />
          </span>
          Fail the next send
        </label>
      </div>

      <SentenceForm
        onSubmit={send}
        className="relative mt-7 min-h-[30rem] text-[22px] leading-[1.5] font-medium tracking-[-0.015em] sm:min-h-[22rem] sm:text-[28px] sm:leading-[1.45]"
        submitLabel="Request demo"
        submitClassName="data-[ready=true]:bg-white data-[ready=true]:text-zinc-950 tracking-normal"
        trayClassName="tracking-normal"
        errorMessage="Couldn't reach our server. Nothing's lost, so try again."
        success={({ values, reset }) => (
          <div className="flex flex-wrap items-center gap-x-4 gap-y-2 tracking-normal">
            <p className="inline-flex items-center gap-2 text-zinc-300">
              <span aria-hidden className="grid size-5 place-items-center rounded-full bg-emerald-400/15 text-emerald-300">
                <svg viewBox="0 0 16 16" className="size-3" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
                  <path d="m3.5 8.5 3 3 6-7" />
                </svg>
              </span>
              <span>
                Demo booked. The invite is on its way to <span className="break-all text-white">{values.email}</span>.
              </span>
            </p>
            <button
              type="button"
              onClick={reset}
              className="cursor-pointer rounded-md text-zinc-400 underline decoration-zinc-600 underline-offset-4 outline-none hover:text-white hover:decoration-zinc-400 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-zinc-400"
            >
              Start over
            </button>
          </div>
        )}
      >
        I want an agent that handles{" "}
        <SentenceFormField
          name="task"
          label="Task"
          placeholder="a task"
          options={["support tickets", "lead research", "invoices", "meeting notes"]}
          custom
          required
        />{" "}
        for{" "}
        <SentenceFormField
          name="team"
          label="Who it's for"
          placeholder="whom"
          options={["just me", "a team of 10", "a company of 500+"]}
          required
        />
        . It should work with{" "}
        <SentenceFormField
          name="tools"
          label="Tools"
          placeholder="your tools"
          options={["Slack", "Gmail", "HubSpot", "Notion", "Linear", "Salesforce"]}
          multiple
          required
        />
        . Send the demo to{" "}
        <SentenceFormField
          name="email"
          label="Work email"
          placeholder="you@company.com"
          type="email"
          autoComplete="email"
          required
        />
        .
      </SentenceForm>
    </section>
  );
}
```
