Prompt composer

Free · MITReact Native · Expo

The input for AI apps: a field that grows with the text on a spring, chips that add phrases to the prompt, and a send button that morphs into a stop square while a job runs.

View as Markdown
Try it on your phone
Scan to open this demo in your phone's browser and use it with your fingers.

Installation

$ npx shadcn@latest add https://goodui.dev/native/r/prompt-composer.json

Then run npx expo install --fix so react-native-reanimated, react-native-svg match your Expo SDK. Files land in components/goodui-native/prompt-composer.

Usage

import { useState } from "react";
import { PromptComposer } from "@/components/goodui-native/prompt-composer/prompt-composer";

const [prompt, setPrompt] = useState("");

<PromptComposer
  value={prompt}
  onChangeText={setPrompt}
  onSubmit={(text) => generate(text)}
  busy={running}
  onStop={cancel}
  chips={[{ id: "studio", label: "Studio light" }, { id: "film", label: "Film grain" }]}
/>

When to use

Use it for
  • Describing what to generate, with optional suggested phrases.
  • A chat reply bar that needs a stop button while the answer streams.
Reach for something else
  • Search: use search-bar.
  • Person-to-person chat: chat-screen has its own composer.

API reference

PropTypeDefault
value*string—
onChangeText*(text: string) => void—
onSubmit*
Send was pressed with text in the field.
(text: string) => void—
busy
A job is running: send morphs into a stop square.
booleanfalse
onStop() => void—
chips
Tappable phrases above the field; a tap appends and the chip fills.
PromptChip[]—
leading
A button left of the field: attach, camera.
ReactNode—
emptyAction
Empty-field action in place of send, usually the voice button.
ReactNode—
footer
Sits under the text, inside the box: a live cost.
ReactNode—
maxLinesnumber6
inputRefRef<ComponentRef<typeof TextInput>>—
labelsPartial<PromptComposerLabels>—
style
Style for the outer container.
StyleProp<ViewStyle>—
testID
Identifier for end-to-end tests.
string—

Motion and haptics

  • The field height springs as lines are added, up to maxLines.
  • The arrow morphs into a stop square on the morph spring.
  • Reduced motion: height and morph changes happen at once.
  • Haptic: select on chips, send on submit, warning on stop.
  • The field height and button morph run on the UI thread.

Accessibility

  • The field uses the placeholder as its label, so keep it descriptive.
  • The send button's label switches to Stop while busy, and it is disabled with no text.
  • Chips expose their selected state.

Notes for AI

  • It is controlled: pass value and onChangeText. Clear the value yourself in onSubmit if you want it cleared.
  • `footer` renders under the text inside the box, a good place for CreditsCost.
  • `emptyAction` replaces send while the field is empty, usually a voice button.
  • Chip text is appended with a comma. A chip is on while its phrase is in the text, so editing the text updates it.
  • Keep it above the keyboard in your own layout; it does not handle the keyboard itself.