Prompt input

Takes the next message for an agent.

Layout

  • stackeddefault

  • inline

States

  • empty

  • order-4812.pdf184 KB

    typing

  • focused

  • Shell. Escape to leave

    shell

  • working

  • 2 queued, sent in order when the agent finishes

    1. QueuedThen draft the reply to Maya
    2. QueuedAnd tag the ticket as refunded

    queued

  • refund-evidence.pngUploading 42%

    Waiting for 1 upload

    uploading

  • order-4812.pdfUpload failed

    order-4812.pdf failed. Remove or retry it

    blocked

  • Out of credits for this workspace

    disabled

Usage

When to use it
Use
A person writes the next turn for an agent: text, @ mentions, / commands, files, a model.
Use
The agent may still be working and the composer must stop it or queue the next message.
Not for
A form field takes a few plain lines with no send. Use Textarea.
Not for
A search box filters a list. Use Input.

Rules

8 rules
Must
Send value.serialized to the model and keep value.mentions; never rebuild the prompt from the editor DOM. Because serialized writes each chip as [label](type:id) and each collapsed paste in full; the DOM holds chip labels and a "Pasted 12 lines" stub.
Must
Drive status from the run: submitted the moment it sends, streaming on the first byte, ready when it ends, and pass generation. Because Send turns into Stop from submitted, Escape stops only while working, and generation keeps a late stop from cancelling the next run.
Never
Put a primary Button in tools or meta; the model picker is PromptInputModel and every other tool variant="ghost". Because Send is the composer's one glass key, and a second one on the same row reads as two next steps.
Never
Control the text with value and setState; read it through onValueChange and drive it through the ref. Because chips are atomic nodes in a contenteditable, and re-rendering its text from state moves the caret and breaks every chip.
Must
Pass every file as an attachment with its status and progress, and onRetryAttachment for a failed one. Because Send waits for uploads and blocks on a failed file with its name in the status line, so nothing a person attached is dropped without a word.
Should
Pass messages written while the agent works as queue={<PromptQueue items={queued}/>}, with onSendQueuedNow and onEditQueued. Because the queue then sits in the composer's shell as a second panel, Enter on an empty prompt sends its head and ArrowUp edits its tail.
Must
Give disabled a disabledReason, and disabledAction when there is a way out. Because a composer that silently refuses input reads as broken; the reason sits in the panel and describes the editor.
Should
Set draftKey per thread, so a reload keeps what the person was writing. Because the draft saves 200ms after the last edit and clears on send; one key across threads would carry one thread's draft into another.

State order

7 states, highest first
1
disabled
2
shell
3
working
4
uploading
5
blocked
6
typing
7
empty

Accessibility

5 checks
The editor is a multi-line textbox named by label, with aria-controls and aria-activedescendant on the @ and / list.
The status line is a status region and describes the editor; uploads, a failed file and an undo are said there.
A chip is one node: Backspace removes it whole and Mod+Z or the Undo link puts it back.
Focus darkens the panel's edge to the focus line; the editor itself draws no ring.
Escape is consumed only when it closes the list, leaves shell mode, cancels a held send or stops the run.

Keyboard

6 keys
Enter
Sends; while working with an empty prompt, sends the queue's head.
Shift+Enter
Breaks the line.
@ and /
Open the mention list, or the command list.
Up, Down, Enter, Tab
Move in the open list and pick.
Escape
Closes the list, leaves shell mode, cancels a held send, stops the run, then blurs.
ArrowUp on empty
Edits the last queued message.

Edge cases

6 edge cases
IME composition
Nothing fires while composing, including Enter.
A paste of 3 lines or 150 characters
Collapses into a "Pasted 12 lines" chip, sent in full; a click expands it.
A paste past maxLength
Refused, with how much fits in the status line.
A file type accept refuses
The drop overlay turns to the failure tint and says what fits before the drop.
Send while uploading
Held: the status line says it sends when they finish, with Cancel.
Phone width
The tools take their own row under 320px; Send stays on the bottom line.

API

14 props
onSubmit
(value: PromptValue, attachments) => void
onValueChange
(value: PromptValue) => void
status, generation, onStop
SendStatus, string | number, (generation) => void default 'ready'
layout
'stacked' | 'inline' default 'stacked'
mentions, commands
MentionItem[], CommandItem[] default []
shell, mode, onModeChange
boolean, 'normal' | 'shell' default false
attachments, onAttach, onRemoveAttachment, onRetryAttachment, accept
Attachment[], handlers, string
tools, meta, voice
ReactNode, ReactNode, PromptInputMicProps
queue, onSendQueuedNow, onEditQueued
ReactNode, () => void, () => boolean
disabled, disabledReason, disabledAction
boolean, ReactNode, ReactNode
draftKey, defaultValue, maxLength
string, string, number default maxLength 100,000
waitingCount, onReviewWaiting
number, () => void default 0
ref
PromptInputHandle
labels
PromptInputLabels default English

Tokens

19 tokens
--shell
#f1f1f0
--paper
#ffffff
--field
#efefef
--line-faint
rgb(5 5 5 / 0.06)
--line-focus
rgb(5 5 5 / 0.32)
--radius-shell
14px
--radius-panel
11px
--shell-inset
3px
--control-sm
26px
--type-body
400 14px/1.5 var(--font-sans)
--type-code
400 calc(14px * var(--mono-scale))/1.5 var(--font-mono)
--type-caption
400 12px/1.35 var(--font-sans)
--text-1
rgb(5 5 5 / 0.80)
--text-2
rgb(5 5 5 / 0.60)
--text-3
rgb(5 5 5 / 0.45)
--fail
#e35e49
--fail-tint
#fbe9e5
--fail-text
#b23c29
--dur-state
160ms

Install

For your coding agent

GitHub

Please star me pookie

141

A new design system every week

Leave your email before you copy the prompt.