Morpha UI

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-input

Examples

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.)

Hi! I'm the Morpha assistant. Ask me how to wire up a chat UI.

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 — the status-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; pass tooltip for 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-input

API 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 labelled Remove attachment.
  • Backspace on an empty textarea removes the most recent attachment.

On this page