Prompt Input
Chat composer for AI products with an autosizing field, toolbar, run states, attachments, a follow-up queue and inline mentions.
Description
PromptInput is the message box at the bottom of an AI chat. It is a compound component: the root renders a <div> that owns the text, the run status and the layout, Shell draws the bordered surface, TextArea is an autosizing <textarea>, and Toolbar holds icon Actions plus a Send button that turns into a stop control while a response streams.
Use it for chat threads, copilots docked in a side panel, "ask about this page" boxes and follow-up fields under a generated answer. Two add-ons ship as separate registry items so the base composer stays light: PromptInputQueue lists follow-up prompts waiting for the current run (built on Motion), and PromptInputTokens swaps the textarea for a field with inline @mentions and /commands (built on the React Aria TokenField).
Don't use it for plain forms. A comment box or a feedback field wants Textarea inside Field, and a single-line search wants Input or Command. If you only need the starter prompts shown above an empty chat, that is Prompt Suggestion.
PromptInput is a Create UI Pro component. Install it with a Pro seat.
Installation
Anatomy
With tokens, PromptInputTokens wraps the content and the suggestion popover, and PromptInputTokens.Input replaces PromptInput.TextArea:
Usage
Examples
Every example is a Pro preview (marked with a Pro badge).
Layouts
layout="stacked" puts the toolbar under the field. inline and compact start as a single 48px row with the actions beside the text, then grow into the stacked shape once the text wraps or an attachment arrives. compact also clips the collapsed row to one line, which suits a follow-up field under an answer.
Variants
variant="primary" is a white surface with a border for page backgrounds. secondary fills the shell with bg-weakest, for composers sitting on an already white panel.
Sizes
size follows the Textarea scale. xs, sm and md set the type to text-ui-control-md, -lg and -xl and grow the minimum field height. Icon buttons are 32px, and 40px on a stacked md composer. Single-row layouts keep 32px buttons at every size so the row stays 48px.
Run status
status drives the send button. submitted shows a spinner and streaming a stop icon, both calling onStop when you pass it. error turns the button red and relabels it "Retry". The field locks while running unless lockInputOnRun={false}, and a visually hidden live region announces each status (override the text with statusLabels).
Pass allowSubmitWhileRunning to keep Send and Enter submitting while a response streams, which is how the queue example below collects follow-ups. Send switches back to a stop button whenever the field is empty.
Toolbar
PromptInput.Action is an icon-only ghost Button sized for the composer. Give each one an aria-label, and a tooltip when the icon is not obvious. Any other control, like a model picker Button, can sit in ToolbarStart or ToolbarEnd.
Attachments
Render ChatAttachment tiles inside PromptInput.Attachments. The row collapses when it is empty, and in the single-row layouts a non-empty row expands the composer. A composer with attachments and no text can still be sent. For the file picker, drop target and image paste, see the ChatAttachmentInput example on the Chat Attachment page.
Queue
PromptInputQueue is a separate item: install it with npx @create-ui/cli add prompt-input-queue. It renders a card above the shell for prompts waiting on the current run. Pass values and onReorder to List and a value to each Item to make rows draggable by their Handle. Focus a handle and press ArrowUp or ArrowDown to move a row from the keyboard.
Row actions show on hover and focus by default and stay visible on touch screens. Set actionsVisibility="always" to pin them.
Mentions and commands
PromptInputTokens is a separate item: install it with npx @create-ui/cli add prompt-input-tokens. It needs react-aria-components 1.21 or newer. usePromptInputTokens tracks the field value and the active trigger. Render a DropdownMenu inside PromptInputTokens.Suggestions and call tokens.insertToken from onAction to turn the typed query into a token.
Keep PromptInput.Toolbar outside PromptInputTokens. The wrapper is a React Aria Autocomplete, so any menu inside it joins the suggestion list. For a composer docked to the bottom of the viewport, pass placement="top start" to Suggestions.
Accessibility
ARIA notes:
- The textarea is labelled "Message" by default. Pass
aria-label(oraria-labelledby) toTextAreaorPromptInputTokens.Inputto name it after your assistant. Sendswitches its name betweensendLabel("Send message"),stopLabel("Stop generating") andretryLabel("Retry"). Its icons arearia-hidden.- The root renders a
role="status"region that announcessubmitted,streaminganderror. Set a status to""instatusLabelsto silence it. - Your own handler runs first: call
event.preventDefault()inTextArea'sonKeyDownto replace the Enter behavior, for example to send withCmd+Enteronly. PromptInput.Actionrenders no name of its own. Give every icon-only action anaria-label.- The queue
Handleis labelled "Reorder queued prompt" and setsaria-keyshortcuts. Each keyboard move is announced ("Moved to position 2 of 3"), customizable withgetMoveAnnouncementonList. - Label queue
Removebuttons with the prompt they remove, since several rows share the default "Remove from queue". - The token field is a React Aria
TokenFieldwitharia-placeholdermirrored fromplaceholder. The suggestions use theMenupattern with virtual focus. See the React Aria Autocomplete docs. - The queue's layout animation and the composer transitions are skipped under
prefers-reduced-motion.
Styling
Tailwind override: pass className to any part. Classes merge with the component's CVA classes via cn().
Data slots and attributes: the component sets these for CSS targeting:
data-slot="prompt-input"on the root, withdata-layout,data-size,data-variant,data-status,data-disabledanddata-expanded(single-row layouts that have grown).data-slot="prompt-input-status"on the visually hidden live region.data-slot="prompt-input-shell"on the surface, withdata-mode("stacked","inline","inlineExpanded","compactCollapsed","compactExpanded"). It stylesdata-state="dragging"when aChatAttachmentInput.Dropzonewraps it withasChild.data-slot="prompt-input-content",data-slot="prompt-input-attachments"anddata-slot="prompt-input-textarea"on the field column.data-slot="prompt-input-toolbar",data-slot="prompt-input-toolbar-start"anddata-slot="prompt-input-toolbar-end"on the toolbar.data-slot="prompt-input-action"on each action anddata-slot="prompt-input-send"on the send button, withdata-status.data-slot="prompt-input-footer"on the footer.data-slot="prompt-input-queue"on the queue card, withdata-actions-visibility.data-slot="prompt-input-queue-list"on the scroll container anddata-slot="prompt-input-queue-item"on each row.data-slot="prompt-input-queue-item-handle"on the handle, withdata-reorder-enabled.data-slot="prompt-input-queue-item-body",-icon,-content,-description,-attachments,-attachments-overflow,-actions,-action,-removeand-moreon the row parts.data-slot="prompt-input-token-input"on the token field, withdata-empty,data-placeholderand React Aria'sdata-disabled.data-slot="prompt-input-token"on each token, withdata-selectedanddata-disabled.data-slot="prompt-input-token-suggestions"on the popover, with React Aria'sdata-placement,data-enteringanddata-exiting.
The root sets --prompt-input-max-height from maxHeight. The stacked field and the token field cap their height with it and scroll past it.
Related Components
- Textarea: a plain multi-line form field with label, hint and validation, without run states.
- Prompt Suggestion: starter prompts for the empty state above the composer.
- Chat Attachment: the file tiles, picker and drop target that plug into
PromptInput.Attachments. - Command: a search-first palette for picking actions, not for writing messages.
API Reference
PromptInput
The root. Owns the text, status and layout, and renders a <div>. Extends React.ComponentProps<"div">. Also exported as PromptInputRoot.
Props
Variants
PromptInput.Shell
The bordered surface and focus ring. Clicking empty space inside it focuses the field. Extends React.ComponentProps<"div">.
Props
PromptInput.Content
The column holding attachments and the field. In the single-row layouts it uses display: contents. Extends React.ComponentProps<"div">.
Props
PromptInput.Attachments
The attachment row. Reports whether it has element children, which expands single-row layouts and allows sending without text. Extends React.ComponentProps<"div">.
Props
PromptInput.TextArea
The autosizing field. Extends React.ComponentProps<"textarea">; value, onChange and disabled are wired to the root. Your onKeyDown runs before the built-in Enter handling.
Props
PromptInput.Toolbar
The action row. Floats at the bottom of a stacked shell and uses display: contents in single-row layouts. ToolbarStart and ToolbarEnd are its leading and trailing groups. All three extend React.ComponentProps<"div">.
Props
PromptInput.Action
An icon-only toolbar button. Extends the Button props and disables itself with the field.
Props
PromptInput.Send
The send, stop and retry button. Extends the Button props. disabled can only add to the built-in rules (nothing to send, running without onStop).
Props
PromptInput.Footer
A centered disclaimer under the composer. Extends React.ComponentProps<"p">.
Props
usePromptInput / usePromptInputValue
Hooks for custom parts inside PromptInput. usePromptInput() returns setValue, submit, stop, status, isRunning, isDisabled, effectiveDisabled, size, variant, layout, mode, hasAttachments and the field refs, and does not re-render on typing. usePromptInputValue() returns value, hasContent and canSubmit, and re-renders on every keystroke.
PromptInputQueue
The queue card, from prompt-input-queue. Must sit inside PromptInput. Extends React.ComponentProps<"div">. Also exported as PromptInputQueueRoot.
Props
PromptInputQueue.List
The scrollable <ul>. With values and onReorder it renders a Motion Reorder.Group. Extends React.ComponentProps<"ul"> without the Motion-conflicting drag and animation handlers.
Props
PromptInputQueue.Item
One row, an <li>. Extends React.ComponentProps<"li"> without value and the Motion-conflicting handlers.
Props
PromptInputQueue.Item.Handle
The drag handle. Starts a pointer drag and moves the row with the arrow keys. Disabled when the list is not reorderable or has one row. Extends the Button props.
Props
PromptInputQueue.Item.Body / Icon / Content / Description
Layout parts of a row. Body is a <div> that stacks when it contains Attachments. Icon is an aria-hidden <span> with a document icon by default. Content is a two-line clamped <p> and Description a secondary <p>. Each extends the props of its element and accepts className and children.
PromptInputQueue.Item.Attachments / AttachmentsOverflow
Attachments is a <div> for small ChatAttachment tiles; placed directly on the row it wraps onto its own line. AttachmentsOverflow is a <span> that renders nothing unless hiddenCount is above zero.
Props
PromptInputQueue.Item.Actions / Action / Remove / More
Actions is the <div> that follows actionsVisibility. Action is a ghost Button, icon-only when it has no children. Remove and More are Actions with a trash and a more icon, labelled "Remove from queue" and "More queue actions". All buttons extend the Button props and disable with the composer.
PromptInputTokens
The token wrapper, from prompt-input-tokens. Wraps React Aria's Autocomplete and renders no DOM. Also exported as PromptInputTokensRoot.
Props
PromptInputTokens.Input
The token field, a replacement for PromptInput.TextArea. Wraps React Aria's TokenField and TokenInput and writes its plain text back to the root. Also exported as PromptInputTokenInput.
Props
PromptInputTokens.Token
An inline token chip. Wraps React Aria's Token. Also exported as PromptInputToken.
Props
PromptInputTokens.Suggestions
A non-modal popover anchored to the active trigger, drawn with the DropdownPopover surface. Extends React Aria's Popover props without triggerRef and getTargetRect. Also exported as PromptInputTokenSuggestions.
Props
usePromptInputTokens
Creates the token state. Also re-exports React Aria's TokenFieldValue.
Props
It returns value, setValue, clear, inputRef, anchor, query, trigger, isOpen, insertToken(text, { value, appendSpace }) and close.