Prompt Input
The AI chat composer — an adaptive input bar with attachments and send.
Overview
PromptInput is the chat composer, built to the Figma input-chat spec on the
kit's Base UI primitives and Cupido tokens. The design is deliberately spare:
attachment previews above the frame, then a single 16px-radius surface row
holding the field and two key buttons — the paperclip and send.
The frame carries every state without reflowing. Hover tints it with an
on-surface-variant/8 state layer; once there is something to send it takes a
1px primary border and the submit button fills with primary (idle it stays a
disabled on-surface/10 chip). The textarea grows with its content and caps at
seven lines, after which it scrolls internally so the composer's height stops
moving.
Underneath it owns the full AI-SDK plumbing: attachment state with drag-and-drop
and paste, a status-aware submit/stop button, and blob→data-url conversion on
submit.
$ npx morpha-ui add prompt-inputExamples
Extended
Everything past this point is an extension beyond the design. The frame
wraps, so a PromptInputFooter dropped inside it takes a second row — enough to
carry a tool cluster, the + action menu and a model picker when a product needs
them.
Chatbot
The whole conversation UI assembled: MessageScroller for the viewport,
Message + Bubble for the rows, Response for the streamed assistant
markdown, and PromptInput for the composer. (This demo streams a canned reply —
swap in useChat to make it live.)
Minimal
Just a textarea and a submit button — the smallest useful composer.
Usage with the AI SDK
PromptInput pairs with useChat. The submit button reflects status
(submitted → spinner, streaming → stop square), and sendMessage receives the
text and files.
"use client";
import { useChat } from "@ai-sdk/react";
import {
PromptInput,
PromptInputAttachButton,
PromptInputAttachment,
PromptInputAttachments,
PromptInputBody,
PromptInputHeader,
PromptInputSubmit,
PromptInputTextarea,
PromptInputTools,
type PromptInputMessage,
} from "@/components/ui/prompt-input";
import { useState } from "react";
export function Composer() {
const [text, setText] = useState("");
const { sendMessage, status } = useChat();
const handleSubmit = (message: PromptInputMessage) => {
if (!(message.text || message.files.length)) return;
sendMessage({ text: message.text, files: message.files });
setText("");
};
return (
<PromptInput onSubmit={handleSubmit} accept="image/*" multiple globalDrop>
<PromptInputHeader>
<PromptInputAttachments>
{(file) => <PromptInputAttachment data={file} />}
</PromptInputAttachments>
</PromptInputHeader>
<PromptInputBody>
<PromptInputTextarea
value={text}
onChange={(e) => setText(e.currentTarget.value)}
/>
<PromptInputTools>
<PromptInputAttachButton />
<PromptInputSubmit status={status} />
</PromptInputTools>
</PromptInputBody>
</PromptInput>
);
}PromptInputSubmit disables itself while the composer is empty and arms as soon
as there is text or an attachment, so it usually needs no disabled prop.
The matching backend route streams a UIMessage response — see the
Response component for rendering the reply.
Anatomy
The parts the design specifies:
PromptInput— the form; owns attachment state and drop/paste, and lays its children out as a column.PromptInputHeader— the row above the frame, where attachment previews go. It collapses while empty.PromptInputBody— the composer frame itself.PromptInputTextarea— auto-growing input (Enter submits, Shift+Enter newlines).PromptInputTools— the trailing button cluster.PromptInputAttachButton— the paperclip, already wired to the file dialog.PromptInputSubmit— thestatus-aware submit / stop button.PromptInputAttachments+PromptInputAttachment— the 60px preview tiles.
Extensions beyond the design, for products that need them:
PromptInputButton— a standard icon button in the composer's style; passtooltipfor a plain tooltip.PromptInputFooter— an optional second row inside the frame.PromptInputActionMenu— the+menu (PromptInputActionAddAttachments).PromptInputSelect— the compact model picker.PromptInputProvider— lifts input + attachments out of the form.
Installation
Distributed via the Morpha CLI: npx morpha-ui add prompt-input. The AI-SDK
plumbing follows AI Elements; the surface is
the kit's own. Depends on ai and nanoid.
npx morpha-ui add prompt-inputAPI Reference
Prop
Type
Accessibility
- The textarea submits on Enter and inserts a newline on Shift+Enter; the submit
button is a real
type="submit"so keyboard users post the form naturally. - The submit control carries an
aria-label, and attachment remove buttons are labelledRemove attachment. - Backspace on an empty textarea removes the most recent attachment.