Chat Empty State
Welcome people to a new conversation with context and suggested prompts.
Installation & usage
npm i @youj/reactFor an app already set up with npx @youj/cli init, which installs the peers (@youj/core, @youj/motion, motion and Base UI) and wires the provider. New app? Start at Installation.
Show it in place of the message list until the first message is sent. It sets expectations (what this assistant can see and do) and offers suggestions so nobody faces a blank field. For empty views elsewhere in an app, use Empty State, the primitive this is built on.
import { ChatEmptyState, ChatMessageList } from '@youj/react'
{messages.length === 0 ? (
<ChatEmptyState
greeting="Good morning, Ada"
description="Ask about your deployments, logs and metrics."
suggestions={starters}
onSelect={(prompt) => {
setDraft(prompt)
composer.current?.focus()
}}
/>
) : (
<ChatMessageList>{/* … */}</ChatMessageList>
)}Suggestions show when both suggestions and onSelect are set, as cards by default (suggestionsLayout="chips" for a row). icon replaces the tile's sparkles, and children render below everything else.
Description
A greeting and four starter prompts above a composer, where picking one fills the composer.
It's one arrival, in order, then stillness. The icon tile's plates fan out, the greeting rises word by word from behind its line, the description fades in once the greeting has landed, and the suggestions stagger in two steps after that. The greeting's word count sets the timing, so a longer greeting pushes the rest back.
Code
chat-empty-state-demo.tsx, the Demo story. The component itself comes from the package.
Reference
Propsgreeting, description, icon… (6)
Props
| Prop | Type | |
|---|---|---|
greetingRequired | stringRevealed word by word, read whole. | – |
description | ReactNode | – |
icon | ReactNodeThe tile's icon. Default: youj's SparklesIcon. | – |
suggestions | ChatSuggestion[] | – |
onSelect | (prompt: string, suggestion: ChatSuggestion) => void | – |
suggestionsLayout | 'chips' | 'cards'default 'cards' | 'cards' |
Other props pass through: extends ComponentProps<'div'>. | ||
MotionGreeting, greeting step, description… · reduced motion
Motion
| Moment | Tokens | ||
|---|---|---|---|
| Greetingeach word rises from behind a mask (TextSplit) | duration.slowease.enter340ms · cubic-bezier(0.16, 1, 0.3, 1) | 340mscubic-bezier(0.16, 1, 0.3, 1) | |
| Greeting stepbetween words | stagger.base40ms step | 40ms step | |
| Descriptionfades in after one step per word | duration.slowease.enter340ms · cubic-bezier(0.16, 1, 0.3, 1) | 340mscubic-bezier(0.16, 1, 0.3, 1) | |
| Suggestionsrise in sequence, from two steps after the description | stagger.base40ms step | 40ms step |
Reduced motion
The greeting, description and suggestions are all in place at once.
Reduced motion
Everything is in place from the first frame: no plates fanning out, no rising words, no stagger.
Accessibilityfocus, announcements
Accessibility
- Screen readers get the greeting whole, not word by word.
- The suggestions are a group of real buttons (see Suggestions). Pick one and move focus to the composer, as the example does.