WebberUI

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.

How to install Pro components →See the plans →

Loading preview…
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.

8
<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

PropTypeDefaultDescription
valuestringControlled text value; when omitted, the component manages it internally
onValueChange(value: string) => voidFires when the text changes (called in both controlled and uncontrolled modes)
onSubmit(payload: PromptSubmitPayload) => voidFires on submit, returning the text, attachments, and model
placeholderstring"問我任何問題⋯" ("Ask me anything…")Placeholder text for the textarea
modelsPromptModel[]List of selectable models; providing it shows the model menu
modelIdstringControlled id of the current model
defaultModelIdstringmodels[0].idDefault model id in uncontrolled mode
onModelChange(modelId: string) => voidFires when the model changes
commandsPromptSuggestion[]List of slash commands shown when / is typed
mentionsPromptSuggestion[]List of mentions shown when @ is typed
allowAttachmentsbooleantrueWhether the attachment button is shown
acceptstringThe file picker's accept attribute
allowVoicebooleantrueWhether the microphone and recording waveform are shown
onVoiceStop(seconds: number) => voidFires when recording ends, passing the number of seconds recorded
streamingbooleanfalseStreaming: the submit button turns into a stop button
onStop() => voidFires when the stop button is pressed during streaming
maxRowsnumber8Maximum number of rows; scrolls inside the textarea beyond that
disabledbooleanfalseDisables the entire input

PromptSubmitPayload

FieldTypeDescription
textstringThe text content, trimmed of leading and trailing whitespace
attachmentsFile[]Files the user attached
modelIdstring | undefinedId 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's popLayout so 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 streaming is true, the submit button swaps to a stop square with a spring animation, and clicking it fires onStop.
  • Controlled and uncontrolled modes: both the text and the model support either mode; when the matching value / modelId is 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 with aria-expanded, aria-controls, and aria-activedescendant to link the suggestion popover, and the candidates are role="option".
  • The model menu is role="menu" with items as role="menuitemradio" carrying aria-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 with aria-pressed, and the recording waveform reports through role="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.

On this page