A hero whose entry point is a prompt box: a small label, a short headline, a lead, a large PromptInput with Enter to send, a status line and example tasks. The placeholder line cycles through example tasks once and settles on the first, a caret in the accent blinks four times and stays, and the status line sweeps a highlight twice while it says the agent is ready. By default the form is a demo that sends nothing: it goes to a demo page with method="get" and the textarea has no name, so a typed prompt never lands in a URL. The section ships no script of its own; Enter to send is PromptInput's measured script.
Live demo
Sample agent · a demo form that sends nothing
Hand the failing build to an agent
Describe a task and press Enter. The examples under the box are links; what you type is never sent.
Fix the failing checkout testUpdate the lockfile and fix what breaksExplain why main is redFix the failing checkout test, Update the lockfile and fix what breaks, Explain why main is red
Live, from the library itself, at full size: scroll, hover, navigate away and back. The demo is never gated.
Variants · each row writes the attribute the prop writes; the section's own CSS answers
tone
density
align
Measured
JavaScript of its own
0 B
Uses PromptInputSubmitOnEnter and the shared runtime (1.9 kB raw, once per site). With those included: 2.0 kB raw.
CSS 26.8 kB raw including the base tokens. Measured from a production build, and again in CI for every change that can move it.
Browser support
Baseline · newly available
Chrome 123 · Firefox 152 · Safari 26.2; needs field-sizing, has, property, bg-clip-text. Elsewhere: without field-sizing the box keeps its rows and a resize handle; without registered properties the example tasks cross-fade in place.
Install Pro
The demo above is never gated; the source is. With a key in components.json (see account), the registry serves it like any other item:
terminal
npx shadcn@latest add @moonarc-pro/hero-prompt
src/pages/index.astro
---import HeroPrompt from '@/components/moonarc/pro/HeroPrompt.astro';---<!-- a demo form: it goes to /demo/ and sends no text. Give it a name and an action of your own to wire it to your app --><HeroPrompt label="Release 2.1" headline="Hand the failing build to an agent" lead="Describe the task. The agent reads the logs, changes the code and asks before it merges." placeholders={['Fix the failing checkout test', 'Update the lockfile', 'Explain why main is red']} status="Ready · 3 repositories connected" examples={[ { label: 'Fix a failing test', href: '/demo/?task=fix-test' }, { label: 'Update dependencies', href: '/demo/?task=update-deps' }, ]} action="/demo/" glow/>
The headline; eight words or fewer read best. The headline slot wins over it.
label
string
none
The small line above the headline, in the monospace face and sentence case. The label slot wins over it.
lead
string
none
The paragraph under the headline. The copy slot wins over it.
placeholders
string[]
['Describe a task']
Example tasks for the placeholder line, up to three. With two or more, the line cycles through them once (4.8 s at most) and settles on the first, which is also the textarea's own placeholder.
status
string
none
The status line under the box while the agent is ready. A highlight sweeps it twice, then it rests.
examples
{ label, href }[]
none
Example tasks under the box, up to four: links to a demo page with the task's slug (/demo/?task=refactor), never the typed text.
examplesLabel
string
'Try'
The word before the examples, which also names their list.
action
string
'/demo/'
Where the form goes. The default is a demo page.
method
'get' | 'post'
'get'
The form's method.
name
string
none
The textarea's name. Unset, it has none and the form sends no text, so a typed prompt never lands in a URL. Set it, with an action of your own, to send the prompt to your app.
promptLabel
string
'Describe a task'
Accessible name of the textarea.
sendLabel
string
'Run'
Visually hidden name of the send button.
rows
number
3
Rows the box shows when empty; it grows with its text to eight.
glow
boolean
false
A soft light from the accent behind the box.
orb
boolean
false
The Orb behind the box, still and dimmed, hidden from screen readers. Wins over glow: one depth cue at most.
level
1 | 2
1
Heading level of the headline: 1 on the page's own hero, 2 under another h1 (a demo).
tone
'surface' | 'muted' | 'ink' | 'brand'
unset (paints nothing)
The ground: the page surface, a muted band, an always-dark ink panel, or a deep brand panel. With theme.css the box and the examples take the tone's card, and their text and edge the tone's text.
density
'compact' | 'cozy' | 'roomy'
'cozy'
Block padding and the gap above the box ×0.8 / ×1 / ×1.25 through --ma-density.
align
'center' | 'start'
'center'
Alignment of the label, the headline, the lead and the examples.
Theming and overrides
The section reads the theme contract (shadcn's variable names with the base tokens as fallback), so a pasted theme or one --ma-brand recolours it. Its class names are the override surface and stay stable; a named slot replaces the matching prop with your own markup.
The first example stands still as the textarea's placeholder: no cycle, no blinking caret and no sweep on the status line.
With ClientRouter
CSS only, and PromptInput's Enter script rebinds through the shared runtime; a new page restarts the cycle.
Why it is built this way
The cycle runs once and comes back to the first example, which is the textarea's own placeholder: after five seconds nothing moves, and reduced motion shows the same line with no motion at all.
The cycling line is drawn over the textarea where its placeholder would be and takes no pointer; the textarea's own placeholder is made transparent through PromptInput's --ma-prompt-placeholder token while the line is drawn, and both give way to typed text.
The accent is only on what is live: the caret, the status dot and the sweep. The send button stays in the text colour.
A demo form sends nothing: no name on the textarea, method="get" to a page. A reader who types a secret into a demo never finds it in the address bar or a server log.
Replaces: Hero with AI input (Lovable style) · PlaceholdersAndVanishInput hero (Aceternity). See the migration table.
Related
grows with the text · Enter sends · ⇧Enter breaks the line
The AI prompt box: a form with a textarea that grows with its content through field-sizing, a model select, an attachment button that is a real file input, and a send button that dims until something is typed and spins while the form carries data-pending.
A highlight sweeps across the text every few seconds.
every browseralways
Sample conversation
Ask, watch it work, approve
An imaginary agent on an imaginary repository. Open a call to read what it returned.
SSample agent
RunningDone
You
Fix the failing checkout test in apps/web
Sample agent
Working
One assertion fails: the total keeps a fraction of a cent. I will find where it is computed.
read_log(job 4182)0.4 s
FAIL apps/web/cart.test.ts
total > rounds to cents
expected 23.99, received 23.988
grep("* 1.2" apps/web/src)0.2 s
apps/web/src/cart/total.ts:3 return sum * 1.2;
run_tests(apps/web)38 s
Tests 48 passed (48)
Time 37.9 s
Sample agent
Push the change to fix/checkout-rounding and open a pull request?
ApproveApproved
Sample agent
Done. The total now rounds to cents after tax, and all 48 tests in apps/web pass. The pull request is open for review.Done.Thetotalnowroundstocentsaftertax,andall48testsinapps/webpass.Thepullrequestisopenforreview.Done. The total now rounds to cents after tax, and all 48 tests in apps/web pass. The pull request is open for review.
SSample agent
RunningDone
You
Update the lockfile and fix what breaks
Sample agent
Working
Three packages have new minor releases. I will update them one at a time and run the suite after each.
Commit the three updates to deps/2026-09 and open a pull request?
ApproveApproved
Sample agent
Updated three packages. One test needed a new date format, which I changed; the other 211 passed as they were.Updatedthreepackages.Onetestneededanewdateformat,whichIchanged;theother211passedastheywere.Updated three packages. One test needed a new date format, which I changed; the other 211 passed as they were.
SSample agent
RunningDone
You
Explain why main is red
Sample agent
Working
The last merge changed a shared type. I will compare the two runs.
list_runs(main, 2)0.3 s
#4190 failed 3 min ago
#4189 passed 41 min ago
diff_runs(4189, 4190)0.8 s
new failure: api/orders.test.ts
Order.total is string, expected number
Sample agent
Open an issue for the author of the merge with this explanation?
ApproveApproved
Sample agent
Main is red because a merge 40 minutes ago made Order.total a string. One test in api/orders expects a number. Reverting that line or parsing it fixes the build.Mainisredbecauseamerge40minutesagomadeOrder.totalastring.Onetestinapi/ordersexpectsanumber.Revertingthatlineorparsingitfixesthebuild.Main is red because a merge 40 minutes ago made Order.total a string. One test in api/orders expects a number. Reverting that line or parsing it fixes the build.
A conversation with an AI agent, replayed in the page: the reader's message, the agent's reply with its tool calls folded into <details> (the call and its result in the monospace face), a request for approval that is approved, and the final answer, typed, with a button that copies it; a prompt box at the foot as a demo form.
Chrome 116 · not Firefox · Safari 18scrollhoverclick