AI Prompt Input Pro
An advanced AI chat input integrating attachments, a model menu, a voice waveform, slash commands, @ mentions, and a streaming stop state.
This is a WebberUI Pro component
Free during the launch campaign: sign up or sign in, then hit “Copy install command” in the preview above and it installs straight away — no payment, no credit card. The command below returns 401 while you are signed out.
npx shadcn@latest add "https://webberui.com/r/ai-prompt-input-pro.json?t=<install token>"Playground
Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.
<AiPromptInputPro />
Installation
npx shadcn@latest add "https://webberui.com/r/ai-prompt-input-pro.json?t=<install token>"Or, once registries are configured in components.json, install it as @webberui/ai-prompt-input-pro.
Usage
import {
AIPromptInputPro,
type PromptSubmitPayload,
} from "@/components/ui/ai-prompt-input-pro";
const models = [
{ id: "opus", label: "Webber Opus", description: "Strongest reasoning" },
{ id: "haiku", label: "Webber Haiku", description: "Fast and lightweight" },
];
const commands = [{ id: "sum", label: "Summarize", description: "Condense the key points" }];
const mentions = [{ id: "alex", label: "Alex", description: "Product design" }];
<AIPromptInputPro
models={models}
commands={commands}
mentions={mentions}
onSubmit={(payload: PromptSubmitPayload) => console.log(payload)}
/>;On submit, onSubmit receives a PromptSubmitPayload containing the text, the attachments, and the current model. Set streaming to true during a streaming response and the submit button turns into a stop button that fires onStop.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
value | string | — | Controlled text value; when omitted, the component manages it internally |
onValueChange | (value: string) => void | — | Fires when the text changes (called in both controlled and uncontrolled modes) |
onSubmit | (payload: PromptSubmitPayload) => void | — | Fires on submit, returning the text, attachments, and model |
placeholder | string | "問我任何問題⋯" ("Ask me anything…") | Placeholder text for the textarea |
models | PromptModel[] | — | List of selectable models; providing it shows the model menu |
modelId | string | — | Controlled id of the current model |
defaultModelId | string | models[0].id | Default model id in uncontrolled mode |
onModelChange | (modelId: string) => void | — | Fires when the model changes |
commands | PromptSuggestion[] | — | List of slash commands shown when / is typed |
mentions | PromptSuggestion[] | — | List of mentions shown when @ is typed |
allowAttachments | boolean | true | Whether the attachment button is shown |
accept | string | — | The file picker's accept attribute |
allowVoice | boolean | true | Whether the microphone and recording waveform are shown |
onVoiceStop | (seconds: number) => void | — | Fires when recording ends, passing the number of seconds recorded |
streaming | boolean | false | Streaming: the submit button turns into a stop button |
onStop | () => void | — | Fires when the stop button is pressed during streaming |
maxRows | number | 8 | Maximum number of rows; scrolls inside the textarea beyond that |
disabled | boolean | false | Disables the entire input |
PromptSubmitPayload
| Field | Type | Description |
|---|---|---|
text | string | The text content, trimmed of leading and trailing whitespace |
attachments | File[] | Files the user attached |
modelId | string | undefined | Id of the model selected at submit time |
How it works
- Slash commands and @ mentions: parsed live from the token under the cursor as you type, with
/only triggering at the start of a sentence or after whitespace. The candidate list is filtered by subsequence fuzzy matching and supports ↑ ↓ to move, Enter / Tab to insert, and Esc to close. - Attachments: presented as a row of chips with filename and size, each individually removable; chips animate in and out with
AnimatePresence'spopLayoutso the gaps close smoothly. - Voice waveform: the microphone button toggles the recording state, during which the textarea is replaced with a live waveform and a timer; clicking again ends it and returns the number of seconds (purely a visual demonstration — no actual recording).
- Streaming state: when
streamingistrue, the submit button swaps to a stop square with a spring animation, and clicking it firesonStop. - Controlled and uncontrolled modes: both the text and the model support either mode; when the matching
value/modelIdis not provided, the component manages it internally. - IME-friendly: pressing Enter mid-composition in Chinese and other languages does not submit by accident; Shift+Enter inserts a newline.
Accessibility
- The textarea uses
role="combobox"together witharia-expanded,aria-controls, andaria-activedescendantto link the suggestion popover, and the candidates arerole="option". - The model menu is
role="menu"with items asrole="menuitemradio"carryingaria-checked; once open it closes on an outside click or on selection. - Every icon button has an
aria-label, the record button marks its state witharia-pressed, and the recording waveform reports throughrole="status". - When the user has "reduce motion" enabled at the system level, the waveform becomes static and the pop-in and displacement degrade to a fade in / fade out.
- Timers and event listeners are all cleaned up on unmount.