Prompt InputPreview
Composable prompt form with text editor, actions, attachments, and submit states.
Overview
PromptInput is a visual form shell for composing chat prompts. It captures prompt text and optional file parts on submit, while the consumer owns sending, cancellation, upload, persistence, and chat state.
PromptInput owns one transient draft for its children. The text editor, attachments, submit button, speech button, and prompt-specific actions coordinate through internal composer state, so consumers do not need to install a prompt-level provider. PromptInputSubmit derives its enabled state from that draft and remains disabled while an attachment is loading, uploading, or failed. Omit status or pass null when idle; pass status="processing" to show a disabled spinner; pass status="streaming" to show an enabled stop button that calls onCancel.
Pass consumer-owned attachment display data to PromptInputAttachments when upload, asset, or send-payload ownership lives outside PromptInput. The list renders the standard attachment UI and contributes attachment lifecycle state to submit readiness without adding those files to onSubmit.files.
Usage
import { Card } from "@tilt-legal/cubitt-components/card";
import {
Attachment,
AttachmentInfo,
AttachmentPreview,
AttachmentRemove,
Attachments,
Conversation,
ConversationContent,
ConversationScrollButton,
Message,
MessageContent,
MessageResponse,
PromptInput,
PromptInputActionAddAttachments,
PromptInputActionMenu,
PromptInputActionMenuContent,
PromptInputActionMenuTrigger,
PromptInputFooter,
PromptInputReasoningSwitcher,
PromptInputSpeechButton,
PromptInputSubmit,
PromptInputTextEditor,
PromptInputTools,
Shimmer,
type PromptInputReasoningLevel,
type UIMessage,
usePromptInputAttachments,
} from "@tilt-legal/cubitt-components/chat-elements";Examples
Default
Omit status or pass null when idle. Pass status="processing" to show a disabled spinner. Pass status="streaming" with onCancel to show an enabled stop button.
const isTextPart = (part: unknown): part is { text: string; type: "text" } =>
typeof part === "object" &&
part !== null &&
"type" in part &&
part.type === "text" &&
"text" in part &&
typeof part.text === "string";
const getMessageText = (message: UIMessage) =>
message.parts
.filter(isTextPart)
.map((part) => part.text)
.join("");
function DefaultPromptInput() {
const [status, setStatus] = useState<"processing" | "streaming" | null>(null);
const [messages, setMessages] = useState<UIMessage[]>([]);
return (
<>
{messages.length > 0 || status !== null ? (
<Card className="h-64">
<Conversation className="min-h-0">
<ConversationContent className="gap-4 p-3">
{messages.map((message) => (
<Message from={message.role} key={message.id}>
<MessageContent>
{message.role === "assistant" ? (
<MessageResponse>
{getMessageText(message)}
</MessageResponse>
) : (
getMessageText(message)
)}
</MessageContent>
</Message>
))}
{status !== null ? (
<Message from="assistant">
<MessageContent>
<Shimmer>Thinking through the matter context...</Shimmer>
</MessageContent>
</Message>
) : null}
</ConversationContent>
<ConversationScrollButton />
</Conversation>
</Card>
) : null}
<PromptInput
onSubmit={({ text, files }) => {
sendMessage({ text, files });
setMessages((current) => [
...current,
{
id: crypto.randomUUID(),
parts: [{ text, type: "text" }],
role: "user",
},
]);
setStatus("processing");
window.setTimeout(() => setStatus("streaming"), 350);
window.setTimeout(() => setStatus(null), 1800);
}}
>
<PromptInputTextEditor placeholder="Ask about the matter..." />
<PromptInputFooter className="justify-end">
<PromptInputSubmit onCancel={() => setStatus(null)} status={status} />
</PromptInputFooter>
</PromptInput>
</>
);
}
<DefaultPromptInput />;Reasoning Switcher
PromptInputReasoningSwitcher cycles through low, medium, high, and xhigh. Keep the selected value in app state and pass it into the chat runtime when sending a prompt.
function ReasoningPromptInput() {
const [reasoning, setReasoning] = useState<PromptInputReasoningLevel>("low");
return (
<PromptInput onSubmit={handleSubmit}>
<PromptInputTextEditor placeholder="Ask about the matter..." />
<PromptInputFooter>
<PromptInputTools>
<PromptInputReasoningSwitcher
onValueChange={setReasoning}
value={reasoning}
/>
</PromptInputTools>
<PromptInputSubmit />
</PromptInputFooter>
</PromptInput>
);
}
<ReasoningPromptInput />;Speech Input
PromptInputSpeechButton writes final and interim speech into PromptInputTextEditor. Use standalone Speech Input when dictation is needed outside a prompt composer.
function SpeechPromptInput() {
return (
<PromptInput onSubmit={handleSubmit}>
<PromptInputTextEditor placeholder="Dictate or type a prompt..." />
<PromptInputFooter className="justify-end">
<PromptInputSpeechButton
aria-label="Dictate prompt"
onAudioRecorded={async (blob) => transcribe(blob)}
/>
<PromptInputSubmit />
</PromptInputFooter>
</PromptInput>
);
}
<SpeechPromptInput />;Attachments
function PromptInputAttachmentsDisplay() {
const attachments = usePromptInputAttachments();
if (!attachments.files.length) {
return null;
}
return (
<Attachments variant="inline">
{attachments.files.map((attachment) => (
<Attachment
data={attachment}
key={attachment.id}
onRemove={() => attachments.remove(attachment.id)}
>
<AttachmentPreview />
<AttachmentInfo />
<AttachmentRemove />
</Attachment>
))}
</Attachments>
);
}
function AttachmentsPromptInput() {
return (
<PromptInput
accept="image/*,.pdf,.doc,.docx,.xls,.xlsx"
multiple
onSubmit={handleSubmit}
>
<PromptInputAttachmentsDisplay />
<PromptInputTextEditor placeholder="Attach evidence and ask a question..." />
<PromptInputFooter>
<PromptInputTools>
<PromptInputActionMenu>
<PromptInputActionMenuTrigger aria-label="Add attachment" />
<PromptInputActionMenuContent>
<PromptInputActionAddAttachments />
</PromptInputActionMenuContent>
</PromptInputActionMenu>
</PromptInputTools>
<PromptInputSubmit />
</PromptInputFooter>
</PromptInput>
);
}
<AttachmentsPromptInput />;API Reference
PromptInput
Root prompt composer form. It owns transient text and attachment draft state for its children. Extends HTML form props except onSubmit and onError.
| Prop | Type | Default | Description |
|---|---|---|---|
onSubmit | (message: PromptInputMessage, event: FormEvent<HTMLFormElement>) => void | Promise<void> | - | Called with prompt text and files. Required. Clears draft after successful submit. |
initialInput | string | "" | Initial text editor value. |
accept | string | - | Accepted file types for the hidden file input, for example image/*,.pdf. |
multiple | boolean | - | Allow selecting multiple files. |
globalDrop | boolean | false | Accept dropped files from the document instead of only the prompt form. |
syncHiddenInput | boolean | false | Legacy native-form flag. File data is still delivered through onSubmit. |
maxFiles | number | - | Maximum number of files in the draft. |
maxFileSize | number | - | Maximum file size in bytes. |
onError | (err: { code: "max_files" | "max_file_size" | "accept"; message: string }) => void | - | Called when file validation rejects one or more files. |
children | React.ReactNode | - | Prompt input children such as editor, footer, tools, and submit button. |
className | string | - | Additional CSS classes for the form. |
PromptInputMessage
Message object passed to PromptInput submit handlers.
| Field | Type | Description |
|---|---|---|
text | string | Current prompt text. |
files | FileUIPart[] | Attached files for the prompt. |
usePromptInputAttachments
Hook for custom attachment UI inside PromptInput.
| Field | Type | Description |
|---|---|---|
files | ChatAttachmentFile[] | Current draft attachment files. |
add | (files: File[] | FileList) => void | Add files to the prompt draft. |
remove | (id: string) => void | Remove a draft file by id. |
clear | () => void | Clear all draft files. |
openFileDialog | () => void | Open the hidden file input. |
fileInputRef | React.RefObject<HTMLInputElement | null> | Ref to the hidden file input. |
LocalReferencedSourcesContext
React context that stores prompt-local referenced source documents. PromptInput provides this context internally.
| Field | Type | Description |
|---|---|---|
sources | (SourceDocumentUIPart & { id: string })[] | Current referenced source documents. |
add | (sources: SourceDocumentUIPart[] | SourceDocumentUIPart) => void | Add one or more referenced sources. |
remove | (id: string) => void | Remove a referenced source by id. |
clear | () => void | Clear referenced sources. |
usePromptInputReferencedSources
Hook for custom referenced-source controls inside PromptInput.
| Return Type | Description |
|---|---|
ReferencedSourcesContext | The prompt-local referenced source store from LocalReferencedSourcesContext. |
PromptInputTextEditor
TipTap-powered text editor for the prompt draft. Extends HTML div props except onChange.
| Prop | Type | Default | Description |
|---|---|---|---|
placeholder | string | "What would you like to know?" | Placeholder shown when the editor is empty. |
onChange | (value: string) => void | - | Called when committed editor text changes. |
className | string | - | Additional CSS classes for the editor root. |
PromptInputBody
Layout passthrough for prompt body content. Extends all HTML div props.
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | - | Body content. |
className | string | - | Additional CSS classes for the wrapper. |
PromptInputHeader
Header addon row for the prompt input. Extends InputGroupAddon props except align.
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | - | Header content. |
className | string | - | Additional CSS classes for the header. |
PromptInputFooter
Footer addon row for tools and submit controls. Extends InputGroupAddon props except align.
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | - | Footer content. |
className | string | - | Additional CSS classes for the footer. |
PromptInputTools
Inline wrapper for prompt tools. Extends all HTML div props.
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | - | Tool buttons or menu triggers. |
className | string | - | Additional CSS classes for the wrapper. |
PromptInputAttachment
Convenience attachment item connected to the prompt draft store. Extends Attachment props except data and onRemove.
| Prop | Type | Default | Description |
|---|---|---|---|
data | ChatAttachmentFile | - | Draft attachment file. Required. |
className | string | - | Additional CSS classes for the attachment. |
PromptInputAttachments
Attachment list connected to the prompt. By default it renders internal draft files. Pass data for consumer-owned attachments such as externally uploaded files. Extends Attachments props except children.
| Prop | Type | Default | Description |
|---|---|---|---|
data | readonly (ChatAttachmentFileData & { id: string })[] | internal draft files | Consumer-owned attachment display data. Lifecycle state contributes to submit readiness but files are not included in onSubmit.files. |
children | (attachment: ChatAttachmentFileData & { id: string }) => ReactNode | default attachment UI | Optional custom renderer for each attachment. |
onCancel | (attachment: ChatAttachmentFileData & { id: string }) => void | - | Called by the default remove control while an attachment is uploading. |
onRemove | (attachment: ChatAttachmentFileData & { id: string }) => void | internal draft remove | Called by the default remove control for removable attachments. |
variant | "grid" | "inline" | "list" | "inline" | Attachment layout variant. |
className | string | - | Additional CSS classes for the attachment list. |
PromptInputActionAddAttachments
Menu item that opens the prompt input file picker. Extends MenuItem props.
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | "Add photos or files" | Menu item label. |
onClick | MenuItemProps["onClick"] | - | Called before the file picker opens; prevent default to skip opening. |
className | string | - | Additional CSS classes for the menu item. |
PromptInputActionAddScreenshot
Menu item that captures a screenshot and adds it as a prompt attachment. Extends MenuItem props.
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | "Take screenshot" | Menu item label. |
onClick | MenuItemProps["onClick"] | - | Called before screenshot capture; prevent default to skip capture. |
className | string | - | Additional CSS classes for the menu item. |
PromptInputActionMenu
Prompt tool menu root. Extends Menu props.
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | - | Menu trigger/content. |
PromptInputActionMenuTrigger
Button trigger for PromptInputActionMenu. Extends Button props.
| Prop | Type | Default | Description |
|---|---|---|---|
mode | ButtonProps["mode"] | "icon" | Button mode. |
size | ButtonProps["size"] | "md" | Button size. |
type | ButtonProps["type"] | "button" | Button type. |
variant | ButtonProps["variant"] | "ghost" | Button variant. |
children | React.ReactNode | plus icon | Custom trigger content. |
className | string | - | Additional CSS classes for the button. |
PromptInputActionMenuContent
Menu content for prompt actions. Extends MenuContent props.
| Prop | Type | Default | Description |
|---|---|---|---|
align | string | "start" | Menu alignment inherited from MenuContent. |
children | React.ReactNode | - | Menu items. |
className | string | - | Additional CSS classes for the content. |
PromptInputActionMenuItem
Generic prompt action menu item. Extends MenuItem props.
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | - | Menu item content. |
className | string | - | Additional CSS classes for the item. |
PromptInputSubmit
Submit button connected to the prompt draft. Extends Button props except mode and size.
| Prop | Type | Default | Description |
|---|---|---|---|
status | "processing" | "streaming" | null | null | Runtime status. processing disables the button and shows a spinner. streaming enables a stop button. |
onCancel | ButtonProps["onClick"] | - | Called when the streaming stop button is activated. |
size | ButtonProps["size"] | "md" | Button size. |
disabled | boolean | derived from draft and status | Override disabled state. processing and unresolved attachments remain disabled. |
variant | ButtonProps["variant"] | derived | Defaults to default when ready to submit and secondary when disabled or streaming. |
type | ButtonProps["type"] | "submit" or "button" | Button type. Defaults to "button" while streaming. |
children | React.ReactNode | submit/status icon | Custom button content. Defaults to submit arrow, spinner, or filled stop icon. |
className | string | - | Additional CSS classes for the button. |
PromptInputSpeechButton
Speech input button wired into the prompt text draft. Extends SpeechInput props.
| Prop | Type | Default | Description |
|---|---|---|---|
tooltip | string | { content: ReactNode; shortcut?: string; side?: TooltipContentProps["side"] } | - | Optional tooltip shown around the speech button. |
onTranscriptionChange | (text: string) => void | - | Called after final transcript text is committed to the editor. |
onInterimTranscriptionChange | (text: string) => void | - | Called after interim transcript text is mirrored into editor state. |
onAudioRecorded | (audioBlob: Blob) => Promise<string> | - | MediaRecorder fallback callback inherited from SpeechInput. |
PromptInputReasoningSwitcher
Button that cycles through prompt reasoning levels.
| Prop | Type | Default | Description |
|---|---|---|---|
value | PromptInputReasoningLevel | - | Controlled reasoning level. |
defaultValue | PromptInputReasoningLevel | "low" | Initial uncontrolled reasoning level. |
onValueChange | (value: PromptInputReasoningLevel) => void | - | Called after the level cycles. |
labels | Partial<Record<PromptInputReasoningLevel, string>> | - | Custom display labels for one or more levels. |
aria-label | string | generated | Accessible label. Defaults to Reasoning: {label}. |
size | ButtonProps["size"] | "md" | Button size. |
type | ButtonProps["type"] | "button" | Button type. |
variant | ButtonProps["variant"] | "ghost" | Button variant. |
className | string | - | Additional CSS classes for the button. |
PromptInputReasoningLevel
| Value | Description |
|---|---|
"low" | Lowest reasoning level. |
"medium" | Medium reasoning level. |
"high" | High reasoning level. |
"xhigh" | Highest reasoning level. |
PromptInputSelect
Select root for prompt controls. Extends Select props.
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | - | Select trigger/content. |
PromptInputSelectTrigger
Prompt-styled select trigger. Extends SelectTrigger props.
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | - | Trigger content. |
className | string | - | Additional CSS classes for the trigger. |
PromptInputSelectContent
Select content for prompt controls. Extends SelectContent props.
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | - | Select items. |
className | string | - | Additional CSS classes for the content. |
PromptInputSelectItem
Select item for prompt controls. Extends SelectItem props.
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | - | Item content. |
className | string | - | Additional CSS classes for the item. |
PromptInputSelectValue
Select value renderer for prompt controls. Extends SelectValue props.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Additional CSS classes for the value. |
PromptInputHoverCard
Hover-card root for prompt controls. Extends PreviewCard props.
| Prop | Type | Default | Description |
|---|---|---|---|
openDelay | number | 0 | Accepted for API parity with hover-card usage; currently rendered through PreviewCard. |
closeDelay | number | 0 | Accepted for API parity with hover-card usage; currently rendered through PreviewCard. |
PromptInputHoverCardTrigger
Trigger for PromptInputHoverCard. Extends PreviewCardTrigger props.
| Prop | Type | Default | Description |
|---|---|---|---|
render | React.ReactElement | - | Custom trigger element to render. |
children | React.ReactNode | - | Trigger content. |
PromptInputHoverCardContent
Content for PromptInputHoverCard. Extends PreviewCardContent props.
| Prop | Type | Default | Description |
|---|---|---|---|
align | string | "start" | Alignment passed to PreviewCardContent. |
className | string | - | Additional CSS classes for the content pane. |
PromptInputTabsList
Unstyled tabs list layout helper. Extends all HTML div props.
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | - | Tab groups. |
className | string | - | Additional CSS classes for the list. |
PromptInputTab
Tab section layout helper. Extends all HTML div props.
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | - | Tab content. |
className | string | - | Additional CSS classes for the tab. |
PromptInputTabLabel
Tab label helper. Extends all HTML h3 props.
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | - | Label content. |
className | string | - | Additional CSS classes for the label. |
PromptInputTabBody
Tab body helper. Extends all HTML div props.
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | - | Body content. |
className | string | - | Additional CSS classes for the body. |
PromptInputTabItem
Tab item helper. Extends all HTML div props.
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | - | Item content. |
className | string | - | Additional CSS classes for the item. |
PromptInputCommand
Prompt command root. Extends Command props.
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | - | Command input/list/content. |
className | string | - | Additional CSS classes for the command. |
PromptInputCommandInput
Prompt command search input. Extends CommandInput props.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Additional CSS classes for the input. |
PromptInputCommandList
Prompt command list. Extends CommandList props.
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | - | Command groups and items. |
className | string | - | Additional CSS classes for the list. |
PromptInputCommandEmpty
Empty command state. Extends CommandEmpty props.
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | - | Empty state content. |
className | string | - | Additional CSS classes for the empty state. |
PromptInputCommandGroup
Command item group. Extends CommandGroup props.
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | - | Group items. |
className | string | - | Additional CSS classes for the group. |
PromptInputCommandItem
Command item. Extends CommandItem props.
| Prop | Type | Default | Description |
|---|---|---|---|
children | React.ReactNode | - | Item content. |
className | string | - | Additional CSS classes for the item. |
PromptInputCommandSeparator
Command separator. Extends CommandSeparator props.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Additional CSS classes for the separator. |