About this animation
A support chat where typing indicators morph into replies, with configurable reply copy, instruction steps, gradient colors, and fonts.
How it works
- One continuous Reanimated shared value drives the full conversation timeline.
- An invisible copy of the first reply measures its natural text size before the visible bubble expands.
- Spring segments morph the 56 × 36 typing surface into the measured message while its dots converge and dissolve.
- Each word fades upward on a 28 ms stagger, and the conversation follows the newest reply.
- Reduced Motion swaps spatial morphs and avatar nods for short opacity transitions.
Why this one
Most typing indicators disappear before a separate message pops in. This version preserves one physical surface from anticipation to answer, repeats that continuity for every reply, and pairs it with a structured support card and contextual action. The result feels connected instead of staged while remaining interruptible through one timeline.
Icons: Lucide (ISC).
Install
npx expo install expo-blur expo-linear-gradient @shopify/react-native-skia react-native-reanimated react-native-workletsUsage
import { TypingToMessage } from './typing-to-message';
export function SupportChat() {
return <TypingToMessage style={{ flex: 1 }} />;
}import { useRef } from 'react';
import {
TypingToMessage,
type TypingToMessageRef,
} from './typing-to-message';
export function BrandedSupportChat() {
const ref = useRef<TypingToMessageRef>(null);
return (
<TypingToMessage
ref={ref}
supportName="Nimbus Support"
brandColors={['#7C5CFF', '#3B82F6']}
firstReply="I can help with that. Let’s refresh the connection first."
onSettingsPress={() => openSettings()}
/>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
supportName | string | 'Support' | Support team shown in the glass header. |
agentName | string | 'Jordan' | Agent name shown above the response. |
agentInitials | string | 'JL' | Initials rendered in the agent avatar. |
userMessage | string | 'My files stopped syncing on my laptop.' | Customer's opening message. |
firstReply | string | 'I can help with that. Let’s refresh the sync connection first.' | First agent response measured before the primary morph. |
stepsTitle | string | 'Quick sync reset' | Heading above the numbered troubleshooting steps. |
steps | readonly [string, string, string] | ['Pause syncing', 'Wait ten seconds', 'Resume and refresh'] | Three concise troubleshooting steps. |
finalReply | string | 'That should reconnect this laptop. You can also review the sync folder.' | Closing agent response. |
linkLabel | string | 'Open sync settings' | Label for the contextual settings action. |
quickReply | string | 'Thanks, that fixed it!' | Quick response inserted by the send button. |
quickReplyResponse | string | 'Perfect — your files should stay in sync now.' | Agent acknowledgment after the quick response. |
placeholder | string | 'Message support…' | Placeholder in the glass composer. |
brandColors | readonly [string, string] | ['#7C5CFF', '#3B82F6'] | Two-color brand gradient. |
fontFamily | string | undefined | Main interface font family. |
mediumFontFamily | string | undefined | Medium interface font family. |
onQuickReply | () => void | undefined | Called after the quick response is inserted. |
onSettingsPress | () => void | undefined | Called when the contextual settings action is pressed. |
sendAccessibilityLabel | string | 'Send quick reply' | Screen-reader label for the send action. |
style | StyleProp<ViewStyle> | undefined | Optional container style. |
testID | string | undefined | Optional test identifier. |
The forwarded ref exposes play(), reset(), and sendQuickReply().
Compatibility
- Expo SDK 58, React Native 0.88, Reanimated 4.7, Worklets 0.13, and Skia 2.14.
- iOS, Android, and web: supported
- Runs in Expo Go because the native dependencies are bundled with Expo SDK 58.
Accessibility
The send control and settings link expose semantic roles and 44 pt minimum targets. Reduced Motion removes bubble morphs, scrolling translations, dot waves, and avatar nods while preserving short fades and the full conversational state change.
Customization notes
The typing and message phases share a coordinated timeline. There is no separate duration for one reduced-motion branch.




