Prompt Input
The composer for a chat: a growing textarea, attached context as removable chips, and a toolbar. Enter sends, Shift+Enter adds a newline, and IME composition is checked first.
src/components/ui/prompt-input.tsxAbout
From the component's own source, where it was written.
The composer for a chat: a growing textarea, a row of attached context, and a toolbar.
Enter sends and Shift+Enter inserts a newline — the convention every chat client shares, and the one users have muscle memory for. IME composition is checked first, or the Enter that confirms a Japanese or Chinese candidate would send the message instead.
Install
npx astralyx-ui add prompt-input
Usage
import { PromptInput } from '@/components/ui/prompt-input'
<PromptInput
context={attached}
onRemoveContext={remove}
toolbar={<ContextPicker sources={sources} … />}
onSubmit={send}
/>Composer
Change the props and the source below follows.
<PromptInput
onSubmit={send}
context={attached}
onRemoveContext={remove}
toolbar={<ContextPicker sources={sources} />}
/>Examples
With context and a model picker
<PromptInput toolbar={…} context={attached} />Streaming
<PromptInput busy onStop={stop} />With a budget
<PromptInput maxLength={200} />API
Generated from the source, so it cannot fall behind the code. One table per exported component, then hooks, functions and types.
PromptInput
Extends Omit<ComponentProps<'div'>, 'onSubmit'>.
| Prop | Type | Default | Description |
|---|---|---|---|
| defaultValue | string | number | readonly string[] | '' | — |
| value | string | — | Controlled and uncontrolled text. |
| onValueChange | (value: string) => void | — | Controlled and uncontrolled text. |
| onSubmit | (value: string) => void | — | Fires on Enter or the send button. Never fires while empty or busy. |
| placeholder | string | 'Ask anything…' | — |
| disabled | boolean | false | — |
| busy | boolean | false | Swaps send for stop and blocks submission while a reply is streaming. |
| onStop | () => void | — | Swaps send for stop and blocks submission while a reply is streaming. |
| context | ContextItem[] | [] | { id, label, icon?, detail? }, rendered as removable chips above the field. |
| onRemoveContext | (id: string) => void | — | — |
| toolbar | ReactNode | — | Leading toolbar slot — a context picker, a model select, an attach button. |
| maxLength | number | — | Budget. The counter only appears past 80%, and turns destructive at the limit. |
| stopLabel | string | 'Stop' | — |
| sendLabel | string | 'Send' | — |
PromptAttachButton
The usual leading toolbar button, for attaching context.
Extends ComponentProps<typeof Button>.
| Prop | Type | Default | Description |
|---|---|---|---|
| color | 'neutral' | 'blue' | 'violet' | 'cyan' | 'green' | 'amber' | 'rose' | 'destructive' | — | — |
| variant | 'link' | 'default' | 'colored' | 'secondary' | 'outline' | 'ghost' | — | — |
| size | 'sm' | 'default' | 'xs' | 'lg' | 'xl' | 'icon-xs' | 'icon-sm' | 'icon' | 'icon-lg' | 'icon-xl' | — | — |
| asChild | boolean | — | Render the child element instead of a <button>, keeping the styles. |
| tint | string | — | Any CSS colour, used instead of a named color set. Fill, text, tint and border are all derived from it, and every variant keeps working. |
| label | string | 'Attach context' | Accessible name and tooltip for the button. |
Types
ContextItem
The composer for a chat: a growing textarea, a row of attached context, and a toolbar.
| Field | Type | Description |
|---|---|---|
| id | string | — |
| label | string | — |
| icon? | ReactNode | — |
| detail? | string | Shown after the label, e.g. a line range or a file size. |
Behaviour
| Topic | Detail | Description |
|---|---|---|
| keyboard | Enter / Shift+Enter | Send and newline. Composition events are checked first, so an IME confirming a candidate does not send. |