A growing message composer with attachments, tools, a model picker and a send button that stops a streaming reply.
Example
import {
PromptInput, PromptInputTools, PromptInputButton, PromptInputSubmit, PromptInputActionMenu,
PromptInputActionAddAttachments, PromptInputSelect,
} from "@elements/ui/prompt-input";
import { Icon } from "@elements/ui/icon";
<PromptInput value={state.text} files={state.files} onSubmit={(m) => send(chat, m)}>
<PromptInputTools>
<PromptInputActionMenu>
<PromptInputActionAddAttachments />
</PromptInputActionMenu>
<PromptInputButton toggle pressed={state.search} tooltip="Search the web" shortcut="⌘K">
<Icon name="globe" /> Search
</PromptInputButton>
<PromptInputSelect value={state.model} options={MODELS} />
</PromptInputTools>
<PromptInputSubmit status={chat.status} onStop={() => stop(chat)} />
</PromptInput>
Parts
| Part |
What it is |
PromptInput |
The form: hidden file input, the box, a header of attachment chips, the textarea, and the footer (default slot). |
.prompt-input-textarea |
Grows from minRows to maxRows. Enter submits, Shift+Enter breaks a line, paste attaches files, Backspace on empty removes the last chip. |
.prompt-input-header |
Attachment and source chips, then slot header. |
PromptInputTools |
A row of tool buttons on the left of the footer. |
PromptInputButton |
A ghost tool button with an optional tooltip, shortcut hint and toggle. |
PromptInputSubmit |
Send. Its icon follows status; with onStop it stops a reply in flight. |
PromptInputActionMenu |
The + menu (a DropdownMenu opening upward). |
PromptInputActionMenuItem |
A plain item in the + menu. |
PromptInputActionAddAttachments |
Add photos or files: opens the file dialog. |
PromptInputActionAddScreenshot |
Take screenshot: captures one frame of a screen the user picks. |
PromptInputSelect |
A quiet NativeSelect for the model. |
PromptInputSpeechButton |
Dictation into the textarea with the Web Speech API; disabled where unsupported. |
PromptInputTabsList / Tab / TabLabel / TabBody / TabItem |
Labelled sections of suggestions, for a hover card or popover. |
.prompt-input-drop |
The Drop files to attach overlay while dragging files over the box. |
Attributes
PromptInput
| Attribute |
Type |
Default |
Description |
value |
string (two-way) |
"" |
The text. |
files |
AttachmentData[] (two-way) |
[] |
Attached files: { id, filename, mediaType, url (blob), size, file }. |
sources |
AttachmentData[] (two-way) |
[] |
Referenced source documents, shown as chips and sent with the message. |
placeholder |
string |
"What would you like to know?" |
Textarea placeholder. |
label |
string |
"Message" |
The textarea's accessible name. |
name |
string |
"message" |
The textarea's name. |
minRows |
number |
2 |
Minimum height in lines. |
maxRows |
number |
8 |
The height where it stops growing and scrolls. |
accept |
string |
"" |
Accepted files: image/*, application/pdf, .md. Empty accepts all. |
multiple |
boolean |
false |
The file dialog takes several files. |
globalDrop |
boolean |
false |
Accept file drops anywhere on the page. |
maxFiles |
number |
0 |
Most files attached at once; 0 is no limit. |
maxFileSize |
number |
0 |
Largest file in bytes; 0 is no limit. |
submitOnEnter |
boolean |
true |
Enter submits; Shift+Enter breaks a line. |
allowEmpty |
boolean |
false |
Submit with no text, files or sources. |
disabled |
boolean |
false |
Disables the textarea and every control in the box. |
autofocus |
boolean |
false |
Focus the textarea when it mounts. |
onSubmit |
(message: { text, files, sources }, e: SubmitEvent) => void | Promise<void> |
() => {} |
Called on submit, with each file's blob url converted to a data url (the File stays attached). Clears when it returns or resolves; keeps everything when it throws or rejects. |
onError |
(err: { code: "max_files" | "max_file_size" | "accept", message: string }) => void |
() => {} |
A file was refused. |
class |
string |
"" |
Extra classes on the form. |
attrs |
Record<string, string | number | boolean | undefined> |
{} |
Other attributes for the form. |
textareaAttrs |
Record<string, string | number | boolean | undefined> |
{} |
Attributes for the textarea: maxlength, aria-describedby, autocomplete. |
onTextareaKeyDown |
(e: KeyboardEvent) => void |
() => {} |
Runs before the built-in keys; preventDefault skips Enter to submit. |
PromptInputActionMenu
| Attribute |
Type |
Default |
Description |
icon |
IconName |
"plus" |
The trigger's icon (PromptInputActionMenuTrigger children). |
label |
string |
"Add" |
The + button's and the menu's name. |
open |
boolean (two-way) |
false |
Whether the menu is open. |
PromptInputSubmit
| Attribute |
Type |
Default |
Description |
status |
"ready" | "submitted" | "streaming" | "error" |
"ready" |
The chat status: enter, spinner, stop square or x. |
onStop |
(() => void) | undefined |
undefined |
Set it and the button stops while submitted or streaming. |
disabled |
boolean |
false |
Not clickable; Enter does not submit either. |
variant |
ButtonVariant |
"primary" |
Button variant. |
label |
string |
"" |
Overrides Submit / Stop. |
size |
"xs" | "sm" | "md" | "lg" |
"sm" |
Icon button size. |
onclick |
(e: MouseEvent) => void |
() => {} |
Runs before the submit when not stopping; e.preventDefault() cancels the send. |
PromptInputButton
| Attribute |
Type |
Default |
Description |
label |
string |
"" |
Accessible name; required for icon-only buttons without a tooltip. |
tooltip |
string |
"" |
Shown on hover and focus. |
shortcut |
string |
"" |
A key hint after the tooltip text. |
tooltipSide |
"top" | "right" | "bottom" | "left" |
"top" |
Tooltip side. |
icon |
boolean |
false |
Square, icon only. |
toggle |
boolean |
false |
A toggle button (aria-pressed). |
pressed |
boolean (two-way) |
false |
Whether the toggle is on. |
variant |
ButtonVariant |
"ghost" |
Button variant. |
onclick |
(e: MouseEvent) => void |
() => {} |
Click handler. |
PromptInputActionAddAttachments
| Attribute |
Type |
Default |
Description |
label |
string |
"Add photos or files" |
Item text. |
PromptInputActionAddScreenshot
| Attribute |
Type |
Default |
Description |
label |
string |
"Take screenshot" |
Item text. |
onSelect |
(e: Event) => void |
() => {} |
Runs first; preventDefault skips the capture. |
PromptInputSelect
| Attribute |
Type |
Default |
Description |
value |
string (two-way) |
"" |
The chosen option. |
options |
NativeSelectOptionData[] |
[] |
{ value, label, group?, disabled? }. |
label |
string |
"Model" |
Accessible name. |
PromptInputSpeechButton
| Attribute |
Type |
Default |
Description |
lang |
string |
"" |
Recognition language; defaults to the page's lang. |
label |
string |
"Voice input" |
Accessible name. |
Slots
| Slot |
Part |
Content |
default |
PromptInput |
The footer: PromptInputTools on the left, PromptInputSubmit on the right. |
header |
PromptInput |
Extra content after the attachment chips. |
default |
PromptInputButton |
Icon and text. |
default |
PromptInputSubmit |
A custom icon in place of the status icon. |
default |
PromptInputActionMenu |
Menu items. |
Keyboard
| Keys |
Action |
Enter |
Submits. Not during IME composition, not while submit is disabled, and not while a reply is generating. |
Shift + Enter |
Inserts a line break. |
Backspace |
In an empty textarea, removes the last attachment. |
Ctrl / Cmd + V |
Pasting files attaches them. |
Tab |
Attachment chips and header content, then the textarea, then tools and submit (DOM order). |
Escape |
Closes an open menu, tooltip or preview. |
Data attributes
| Attribute |
Values |
On |
Description |
data-dragging |
present |
.prompt-input-box |
Files are being dragged over it. |
data-pending |
present |
.prompt-input-box |
An async onSubmit is running. |
data-disabled |
present |
.prompt-input |
|
data-status |
"ready" | "submitted" | "streaming" | "error" |
.prompt-input-submit |
|
data-state |
"on" | "off" |
.prompt-input-button (toggle) |
|
data-listening |
present |
.prompt-input-speech |
|
Accessibility
- The textarea is named by label (Message). The file input is hidden from the tab order and named Upload files.
- Submit is named Submit, or Stop while a reply is submitted or streaming, and sets aria-busy while submitted.
- Attachments are a list of chips; each remove button is named Remove
<file> and returns focus to the textarea.
- Tool buttons carry aria-label and aria-pressed; tooltips describe them.
- Disabled uses a disabled fieldset, so every control inside is disabled natively, and the box takes no dropped, pasted or chosen files.
- File errors go to onError; the caller decides how to show them (a toast, a field message).
See also
- Icon (opens in a new tab): An inline stroke icon from the set the templates draw their own controls with, sized in pixels and colored by the text around it.
- Message (opens in a new tab): One chat message with avatar, author, time, streaming Markdown, attachments, actions and response branches.
- MessageList (opens in a new tab): A conversation that stays pinned to the newest message unless the reader scrolls up.
- Attachment (opens in a new tab): A file or source as a thumbnail, chip or row, with preview, size, upload progress and remove.