React Prompt Composer
The input looks trivial and isn't. It has to honour the keyboard conventions people reach for without thinking, grow with the content, show the token budget before a request fails, and never let the same key both send a message and interrupt a reply.
Enter sends, Shift+Enter adds a newline. Sending flips the button to Stop for a moment. The token counter tracks against the selected model’s context window.
Installation
Props
| Prop | Type | Description |
|---|---|---|
| models | ComposerModel[] | { id, label, contextTokens } for the picker |
| tools | ComposerTool[] | { id, label, icon? } toggle chips |
| streaming | boolean | Swap Send for Stop while a reply is in flight |
| onSubmit | (text, { model, tools }) => void | Fires on send |
| onStop | () => void | Fires when Stop is pressed |
| value / onChange | string / (t) => void | Optional controlled value |
Keyboard first
Enter sends; Shift+Enter is a newline — the convention every chat app has trained people into, and getting it wrong is instantly felt. IME composition is respected, so composing CJK text and pressing Enter to confirm a candidate doesn't fire the message off half-written. The textarea grows with its content up to about seven lines, then scrolls, so a long paste never swallows the page.
Honest about the budget
The token estimate runs against the selected model's context window and changes colour before it's a problem — amber past 80%, red and send-disabled once the prompt alone would overflow the window. It's an estimate (characters ÷ 4), clearly a guide rather than the tokenizer's word, but it's the difference between a considered edit and a request that fails on submit. Swapping the model re-evaluates against the new budget. While a reply streams, the send affordance becomes Stop: one control, one meaning at a time.
New components every week
Get the week's new Kelvin UI components and templates in one short email. No spam, unsubscribe anytime.