React AI chat UI components
The interface layer for an LLM product: the prompt box, the thinking state, the model picker and the attachments. Bring your own provider.
Built with the stack you already ship
Prompt input and controls
The parts a user actually touches: where they type, what they attach, and which model they are talking to.
Liquid Multimodal InputAn expanding prompt area with a glowing drop zone that breathes open to meet you as you type a thought or drag a file.
Model Context SwitcherA Radix dropdown that scales out from its trigger and glides the selection pill across to meet whichever model you pick.- Text AreaText AreaAn accessible multi-line field with auto-resize, character counts, validation states, and variants for notes or prompts.
- AttachmentAttachmentFile attachment rows for uploads, chats, and media previews, with download actions and per-type document icons.
- CommandCommandA command palette with fuzzy search, grouped actions, keyboard shortcuts, and fast navigation built on top of cmdk.
- KbdKbdKeyboard key styling for shortcuts, hotkey hints, documentation, and inline command labels anywhere in your app.
Thinking, streaming and voice states
An LLM response takes seconds, not milliseconds. These are the states that fill that gap without making the wait feel broken.
Generative Skeleton MeshAn organic loading state instead of a spinner, with a slow aurora that breathes in the space where your content will land.
Voice Aurora WaveA breathing voice orb that swells with speech and settles between turns, never jittery and always organic to look at.
Chatgpt OrbLow-power WebGL fractal noise that blooms white ink inside a soft circular mask.
Siri OrbA glassy WebGL sphere with a prism ribbon sweeping a full spectrum through it.
Shimmering Skeleton WrapperOne angled GPU sweep that travels across any placeholder geometry you wrap, never a separate shimmer stuttering per row.
Text ShimmerA CSS shimmer sweep for headlines, one single element and entirely GPU-friendly.
Retro Terminal EmulatorCRT phosphor glow, scanlines, and a 240 char/sec typer that never re-renders a single line of output mid-stream.
What makes a chat interface feel good
The hard part of a chat interface is not the message bubbles. It is the several seconds between the user pressing enter and the first token arriving, which is far longer than any normal interface delay and completely outside your control. Everything that makes an AI product feel fast or slow happens in that window, and a plain spinner is the weakest thing you can put there because it says only that something is happening.
A better waiting state suggests the shape of what is coming. That is what a skeleton does in a normal app, and it works here too: Generative Skeleton Mesh fills the response area with something that reads as text taking form rather than as a loading indicator sitting on an empty box. The user's eye settles where the answer will appear, so when tokens do start arriving there is no jump and no re-reading.
Once tokens start streaming, resist the urge to animate them. Text that fades or slides in per word is much harder to read than text that simply appears, because the eye keeps re-fixating on moving targets. Stream the characters in plainly and spend the motion budget on the container instead, letting it grow smoothly as content fills it so the page below does not jump on every chunk.
The prompt input carries more weight than its size suggests, because it is the one thing on screen at every moment. It needs to grow with the content rather than scroll internally, accept a paste of five hundred words without breaking the layout, submit on Enter while keeping Shift and Enter for a newline, and make attachment state obvious before submission rather than after. Liquid Multimodal Input handles all four, which is roughly the minimum bar.
Voice interfaces need one honest signal above all: whether the microphone is currently listening. That is a privacy question before it is a design question, and an ambiguous indicator is worse than none. Voice Aurora Wave ties its amplitude to real input level, so the visual is driven by what the microphone actually hears rather than a decorative loop that would keep moving if the stream had already dropped.
