# Hero 3: AI product with live prompt

> Hero for AI products: a real prompt input on the left, and on the right a mock answer with a reasoning panel, a tool call and a streaming reply.

A shadcn/ui block from the [@ballmac](https://ui.ballmac.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/ballmac/hero-3).

- Page, with a live preview: https://shadcn.exchange/r/ballmac/hero-3
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/ballmac/hero-3-light-6816e3d0c3bb647a.png
- Registry item: https://ui.ballmac.com/r/hero-3.json
- Categories: blocks, hero
- Listed: 2026-10-14, source last changed 2026-10-14

## Install

```bash
npx shadcn@latest add https://ui.ballmac.com/r/hero-3.json
```

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

## Dependencies

- npm packages: `lucide-react`
- Registry items: `utils`, `https://ui.ballmac.com/r/badge.json`, `https://ui.ballmac.com/r/prompt-input.json`, `https://ui.ballmac.com/r/reasoning-disclosure.json`, `https://ui.ballmac.com/r/streaming-text.json`, `https://ui.ballmac.com/r/tool-call-card.json`, `https://ui.ballmac.com/r/media.json`

## Files

### `registry/ballmac/components/blocks/hero-3/hero-3.tsx`

```tsx
// Ballmac UI: Hero 3. https://ui.ballmac.com/blocks/hero-3
"use client"

import * as React from "react"
import { Sparkles } from "lucide-react"

import { Badge } from "@/components/ballmac/badge"
import { PromptInput, PromptInputSubmit, PromptInputTextarea, PromptInputToolbar } from "@/components/ballmac/prompt-input"
import { ReasoningDisclosure } from "@/components/ballmac/reasoning-disclosure"
import { StreamingText } from "@/components/ballmac/streaming-text"
import { ToolCallCard } from "@/components/ballmac/tool-call-card"
import { cn } from "@/lib/utils"
import { Media, type MediaSource } from "@/components/ballmac/media"

type Hero3Props = Omit<React.ComponentProps<"section">, "title" | "onSubmit"> & {
  /** Label above the headline. */
  eyebrow?: string
  /** The headline. */
  title?: string
  /** One or two sentences under the headline. */
  description?: string
  /** Placeholder for the demo prompt. */
  placeholder?: string
  /** Called when a visitor submits the prompt, e.g. to route them to sign-up with their question. */
  onSubmit?: (value: string) => void
  /** Your product image instead of the sample conversation. An image URL (give it mediaAlt), an object with alt text and a dark-mode file, or your own element. */
  media?: MediaSource
  /** Describes `media` when it is a plain URL. */
  mediaAlt?: string
}

const ANSWER = "Revenue grew 18% quarter over quarter, driven by annual plans. Churn fell to 2.1%, the lowest this year."

function Hero3({
  eyebrow = "AI analyst",
  title = "Ask your data anything.",
  description = "Type a question in plain English. The assistant finds the right tables, runs the queries and explains the answer with sources.",
  placeholder = "How did revenue change last quarter?",
  onSubmit,
  media,
  mediaAlt,
  className,
  ...props
}: Hero3Props) {
  return (
    <section data-slot="hero-3" className={cn("relative isolate overflow-hidden", className)} {...props}>
      <div className="mx-auto grid max-w-6xl items-center gap-12 px-4 py-20 sm:px-6 md:py-28 lg:grid-cols-2">
        <div>
          <Badge variant="outline" className="gap-1.5 rounded-full px-3 py-1">
            <Sparkles className="size-3.5" aria-hidden="true" />
            {eyebrow}
          </Badge>
          <h1 className="mt-6 text-4xl font-semibold tracking-[-0.04em] text-balance sm:text-5xl lg:text-6xl">{title}</h1>
          <p className="mt-6 max-w-xl text-lg leading-relaxed text-pretty text-muted-foreground">{description}</p>
          <PromptInput className="mt-8 max-w-xl" onSubmit={(v) => onSubmit?.(v)}>
            <PromptInputTextarea placeholder={placeholder} aria-label="Ask a question" />
            <PromptInputToolbar>
              <span className="px-2 text-xs text-muted-foreground">Press Enter to ask</span>
              <PromptInputSubmit className="ms-auto" />
            </PromptInputToolbar>
          </PromptInput>
        </div>
        <Media media={media} alt={mediaAlt} frame priority fallback={
        <div className="space-y-3 rounded-2xl border bg-card p-5 shadow-[0_30px_80px_-40px_rgb(0_0_0/0.35)] sm:p-6">
          <p className="ms-auto w-fit max-w-[85%] rounded-xl rounded-ee-sm bg-muted px-3.5 py-2 text-sm">{placeholder}</p>
          <ReasoningDisclosure duration={4} defaultOpen={false}>
            Revenue lives in the invoices table; churn in subscriptions. Compare Q3 against Q2 and group by plan.
          </ReasoningDisclosure>
          <ToolCallCard name="run_sql" status="success" duration={318} input={{ query: "select plan, sum(amount) from invoices group by plan" }} result="3 rows" />
          <div className="text-sm leading-7">
            <StreamingText text={ANSWER} animate speed={50} />
          </div>
        </div>
        } />
      </div>
    </section>
  )
}

export { Hero3, type Hero3Props }
```
