suiss/ui
  • Docs
  • Components
  • Patterns
  • Interactions
  • Charts
  • Blocks
  • AI
GitHubCreate
DocsComponentsPatternsInteractionsChartsBlocksAICreate
AI21
  • Overview
Conversation
  • Chat
  • Message
  • Prompt Input
  • Suggestion
  • Model Selector
  • Context
  • Checkpoint
  • Inline Citation
Agent steps
  • Chain of Thought
  • Reasoning
  • Tool
  • Confirmation
  • Task
  • Plan
  • Queue
  • Subagent
  • Sources
Output
  • Terminal
  • Stack Trace
  • Test Results
  • File Tree

suiss/ui · AI

Prompt Input

The field people type into to message an agent, with attachments, model menus and a send button.

"use client"

import {
  ArrowUpIcon,
  CaretDownIcon,
  FileTextIcon,
  PlusIcon,
  XIcon,
} from "@phosphor-icons/react"
import * as React from "react"
import {
  Attachment,
  AttachmentAction,
  AttachmentActions,
  AttachmentContent,
  AttachmentMedia,

Prompt Input is the field the person types into to message the agent. It is an Input Group with a textarea, an attach button, the Model Selector menus and a send button. Attached files show as Attachment chips above the text.

Installation

Prompt Input is built with Input Group, Attachment and Dropdown Menu.

$ pnpm dlx shadcn@latest add @esuiss/input-group @esuiss/attachment @esuiss/dropdown-menu

Or use the suiss/ui CLI:

$ pnpm dlx @esuiss/ui@latest add input-group attachment dropdown-menu

Usage

import {
  InputGroup,
  InputGroupAddon,
  InputGroupButton,
  InputGroupTextarea,
} from "@/components/ui/input-group"
<form ref={formRef} onSubmit={onSubmit}>
  <InputGroup>
    <InputGroupTextarea
      value={text}
      onChange={(event) => setText(event.target.value)}
      placeholder="Ask the agent to change your code..."
      aria-label="Message"
      className="p-3"
    />
    <InputGroupAddon align="block-end">
      <InputGroupButton
        size="icon-sm"
        variant="outline"
        className="rounded-full"
        aria-label="Attach files"
        onClick={() => inputRef.current?.click()}
      >
        <PlusIcon />
      </InputGroupButton>
      <InputGroupButton
        type="submit"
        size="icon-sm"
        variant="default"
        className="ms-auto rounded-full"
        disabled={!canSend}
        aria-label="Send"
      >
        <ArrowUpIcon />
      </InputGroupButton>
    </InputGroupAddon>
  </InputGroup>
</form>

The attach button opens a hidden file input. Show each file as an Attachment in an addon with align="block-start", with a button to remove it.

Put the two Model Selector menus in the block-end addon, between the attach and send buttons. Move ms-auto from the send button to the first menu trigger, so both menus sit next to the send button.

Enter sends the message and Shift+Enter adds a new line:

onKeyDown={(event) => {
  if (event.key === "Enter" && !event.shiftKey) {
    event.preventDefault()
    formRef.current?.requestSubmit()
  }
}}

AI SDK

Send the text and the FileList from the file input.

sendMessage({ text, files })

The route streams the reply with result.toUIMessageStreamResponse().

API Reference

See Input Group, Attachment and Dropdown Menu.

Accessibility

  • Give the textarea an accessible name such as "Message", since the placeholder is not a label.
  • Name each remove button after its file, such as "Remove settings-page.tsx".
  • Disable the send button while the field is empty.
import { ArrowUpIcon, CaretDownIcon, FileTextIcon, PlusIcon, XIcon } from "phosphor-react-native"
import { View } from "react-native"
import { Attachment, AttachmentAction, AttachmentActions, AttachmentContent, AttachmentMedia, AttachmentTitle } from "@/components/ui/attachment"
import { Icon } from "@/components/ui/icon"
import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupTextarea } from "@/components/ui/input-group"
import { Text } from "@/components/ui/text"

export function AiPromptInputExample() {
  return (
    <InputGroup>
      <InputGroupAddon align="block-start">
        <Attachment size="xs">
          <AttachmentMedia>
            <Icon as={FileTextIcon} />
          </AttachmentMedia>
          <AttachmentContent>
import EsuissUI
import PhosphorSwift
import SwiftUI

struct PromptInputExample: View {
  @State private var message = ""

  var body: some View {
    InputGroup {
      InputGroupAddon(align: .blockStart) {
        Attachment(size: .xs) {
          AttachmentMedia { Ph.fileText.regular }
          AttachmentContent { AttachmentTitle("settings-page.tsx") }
          AttachmentActions { AttachmentAction("Remove", icon: Ph.x.bold) {} }
        }
      }
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import com.adamglin.PhosphorIcons
import com.adamglin.phosphoricons.Regular
import com.adamglin.phosphoricons.regular.ArrowUp
import com.adamglin.phosphoricons.regular.FileText
import com.adamglin.phosphoricons.regular.Plus
import com.adamglin.phosphoricons.regular.X
import com.esuiss.ui.components.Attachment
import com.esuiss.ui.components.AttachmentAction

Prompt Input on mobile is built from the same parts as on the web: Input Group, Attachment. The example above is a static demo; connect it to your agent by rendering the same parts from your messages.

Installation

$ pnpm dlx @esuiss/ui@latest add input-group attachment
$ pnpm dlx @esuiss/ui@latest add input-group attachment --platform swift
$ pnpm dlx @esuiss/ui@latest add input-group attachment --platform kotlin

API Reference

See Input Group, Attachment.

NextSuggestionPreviousMessage

On this page

  1. 01Installation
  2. 02Usage
  3. 03AI SDK
  4. 04API Reference
  5. 05Accessibility
  6. 06Installation
  7. 07API Reference