The most complete chat UI for React Native & Web
[!NOTE] Active development has moved. This package is now in maintenance mode and isn't receiving new features. Development continues - including streaming AI messages and the latest fixes - in a maintained fork: @kesha-antonov/react-native-chat. New projects are encouraged to use it; migrating is mostly a rename (see the fork's migration guide).
|
|
|
Le Reacteur - Coding Bootcamp in Paris co-founded by Farid Safi
Stream - Scalable chat API/Server written in Go (API Tour | Tutorial)
Ethora - A complete app engine featuring GiftedChat (GitHub)
📚 React Key Concepts (2nd ed.)
| Requirement | Version |
|---|---|
| React Native | >= 0.70.0 |
| iOS | >= 13.4 |
| Android | API 21+ (Android 5.0) |
| Expo | SDK 50+ |
| TypeScript | >= 5.0 (optional) |
npx expo install react-native-gifted-chat react-native-reanimated react-native-gesture-handler react-native-safe-area-context react-native-keyboard-controller
Step 1: Install the packages
Using yarn:
yarn add react-native-gifted-chat react-native-reanimated react-native-gesture-handler react-native-safe-area-context react-native-keyboard-controller
Using npm:
npm install --save react-native-gifted-chat react-native-reanimated react-native-gesture-handler react-native-safe-area-context react-native-keyboard-controller
Step 2: Install iOS pods
npx pod-install
Step 3: Configure react-native-reanimated
Follow the react-native-reanimated installation guide to add the Babel plugin.
import React, { useState, useCallback, useEffect } from 'react'
import { GiftedChat } from 'react-native-gifted-chat'
import { useHeaderHeight } from '@react-navigation/elements'
export function Example() {
const [messages, setMessages] = useState([])
// keyboardVerticalOffset = distance from screen top to GiftedChat container
// useHeaderHeight() returns status bar + navigation header height
const headerHeight = useHeaderHeight()
useEffect(() => {
setMessages([
{
_id: 1,
text: 'Hello developer',
createdAt: new Date(),
user: {
_id: 2,
name: 'John Doe',
avatar: 'https://placeimg.com/140/140/any',
},
},
])
}, [])
const onSend = useCallback((messages = []) => {
setMessages(previousMessages =>
GiftedChat.append(previousMessages, messages),
)
}, [])
return (
<GiftedChat
messages={messages}
onSend={messages => onSend(messages)}
user={{
_id: 1,
}}
keyboardAvoidingViewProps={{ keyboardVerticalOffset: headerHeight }}
/>
)
}
💡 Tip: Check out more examples in the
exampledirectory including Slack-style messages, quick replies, and custom components.
Messages, system messages, and quick replies follow the structure defined in Models.ts.
Message Object Structure
interface IMessage {
_id: string | number
text: string
createdAt: Date | number
user: User
image?: string
video?: string
audio?: string
system?: boolean
sent?: boolean
received?: boolean
pending?: boolean
quickReplies?: QuickReplies
}
interface User {
_id: string | number
name?: string
avatar?: string | number | (() => React.ReactNode)
}
messages (Array) - Messages to displayuser (Object) - User sending the messages: { _id, name, avatar }onSend (Function) - Callback when sending a messagemessageIdGenerator (Function) - Generate an id for new messages. Defaults to a simple random string generator.locale (String) - Locale to localize the dates. You need first to import the locale you need (ie. require('dayjs/locale/de') or import 'dayjs/locale/fr')colorScheme ('light' | 'dark') - Force color scheme (light/dark mode). When set to 'light' or 'dark', it overrides the system color scheme. When undefined, it uses the system color scheme. Default is undefined.messagesContainerRef (FlatList ref) - Ref to the flatlisttextInputRef (TextInput ref) - Ref to the text inputkeyboardProviderProps (Object) - Props to be passed to the KeyboardProvider for keyboard handling. Default values:statusBarTranslucent: true - Required on Android for correct keyboard height calculation when status bar is translucent (edge-to-edge mode)navigationBarTranslucent: true - Required on Android for correct keyboard height calculation when navigation bar is translucent (edge-to-edge mode)disableKeyboardProvider (Bool) - Skip rendering the built-in KeyboardProvider wrapper; default is false. Enable this when your app already mounts its own KeyboardProvider (e.g. once at the root), or when the default edge-to-edge behavior causes a layout shift, flicker on mount, or a header/content jump on Android/Expo. See Using your own KeyboardProvider below.keyboardAvoidingViewProps (Object) - Props to be passed to the KeyboardAvoidingView. See keyboardVerticalOffset below for proper keyboard handling.isAlignedTop (Boolean) Controls whether or not the message bubbles appear at the top of the chat (Default is false - bubbles align to bottom)isInverted (Bool) - Reverses display order of messages; default is truekeyboardVerticalOffsetThe keyboardVerticalOffset tells the KeyboardAvoidingView where its container starts relative to the top of the screen. This is essential when GiftedChat is not positioned at the very top of the screen (e.g., when you have a navigation header).
Default value: insets.top (status bar height from useSafeAreaInsets()). This works correctly only when GiftedChat fills the entire screen without a navigation header. If you have a navigation header, you need to pass the correct offset via keyboardAvoidingViewProps.
What the value means: The offset equals the distance (in points) from the top of the screen to the top of your GiftedChat container. This typically includes:
- Status bar height
- Navigation header height (on iOS, useHeaderHeight() already includes status bar)
How to use:
import { useHeaderHeight } from '@react-navigation/elements'
function ChatScreen() {
// useHeaderHeight() returns status bar + navigation header height on iOS
const headerHeight = useHeaderHeight()
return (
<GiftedChat
keyboardAvoidingViewProps={{ keyboardVerticalOffset: headerHeight }}
// ... other props
/>
)
}
Note:
useHeaderHeight()requires your chat component to be rendered inside a proper navigation screen (not conditional rendering). If it returns0, ensure your chat screen is a real navigation screen with a visible header.
Why this matters: Without the correct offset, the keyboard may overlap the input field or leave extra space. The KeyboardAvoidingView uses this value to calculate how much to shift the content when the keyboard appears.
KeyboardProviderBy default GiftedChat wraps itself in a KeyboardProvider with statusBarTranslucent and navigationBarTranslucent enabled. On some Android/Expo (edge-to-edge) setups this can cause the screen to shift down, flicker on mount, or distort a navigation header - especially when another KeyboardProvider already exists higher in the tree.
Set disableKeyboardProvider to skip the built-in wrapper:
```jsx import { KeyboardProvider
$ claude mcp add react-native-gifted-chat \
-- python -m otcore.mcp_server <graph>