The project's README from github.com/FaridSafi/react-native-gifted-chat. As one markdown file: README.md.
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.
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:
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:
import { KeyboardProvider } from 'react-native-keyboard-controller'
// Mount a single KeyboardProvider once, near the root of your app
function App() {
return (
<KeyboardProvider>
{/* ...navigation / screens... */}
</KeyboardProvider>
)
}
function ChatScreen() {
return (
<GiftedChat
disableKeyboardProvider
// ... other props
/>
)
}
Important: GiftedChat's keyboard avoidance relies on a
KeyboardProviderbeing present in the tree. When you setdisableKeyboardProvider, you must mount your ownKeyboardProviderabove GiftedChat - otherwise the keyboard will cover the input. Mounting exactly one provider (yours) is what avoids the double edge-to-edge shift.
text (String) - Input text; default is undefined, but if specified, it will override GiftedChat's internal state. Useful for managing text state outside of GiftedChat (e.g. with Redux). Don't forget to implement textInputProps.onChangeText to update the text state.initialText (String) - Initial text to display in the input fieldisSendButtonAlwaysVisible (Bool) - Always show send button in input text composer; default false, show only when text input is not emptyisTextOptional (Bool) - Allow sending messages without text (useful for media-only messages); default false. Use with isSendButtonAlwaysVisible for media attachments.minComposerHeight (Object) - Custom min-height of the composer.maxComposerHeight (Object) - Custom max height of the composer.minInputToolbarHeight (Integer) - Minimum height of the input toolbar; default is 44renderInputToolbar (Component | Function) - Custom message composer containerrenderComposer (Component | Function) - Custom text input message composerrenderSend (Component | Function) - Custom send button; you can pass children to the original Send component quite easily, for example, to use a custom icon (example)renderActions (Component | Function) - Custom action button on the left of the message composerrenderAccessory (Component | Function) - Custom second line of actions below the message composertextInputProps (Object) - props to be passed to the <TextInput>.onPressActionButton (Function) - Callback when the Action button is pressed (if set, the default actionSheet will not be used)actionSheet (Function) - Custom action sheet interface for showing action optionsactions (Array) - Custom action options for the input toolbar action button; array of objects with title (string) and action (function) propertiesactionSheetOptionTintColor (String) - Tint color for action sheet optionsmessagesContainerStyle (Object) - Custom style for the messages containerrenderMessage (Component | Function) - Custom message containerrenderLoading (Component | Function) - Render a loading view when initializingrenderChatEmpty (Component | Function) - Custom component to render in the ListView when messages are emptyrenderChatFooter (Component | Function) - Custom component to render below the MessagesContainer (separate from the ListView)listProps (Object) - Extra props to be passed to the messages <FlatList>. Supports all FlatList props including maintainVisibleContentPosition for keeping scroll position when new messages arrive (useful for AI chatbots).renderBubble (Component | Function(props: BubbleProps)) - Custom message bubble. Receives BubbleProps as parameter.renderMessageText (Component | Function) - Custom message textrenderMessageImage (Component | Function) - Custom message imagerenderMessageVideo (Component | Function) - Custom message videorenderMessageAudio (Component | Function) - Custom message audiorenderCustomView (Component | Function) - Custom view inside the bubbleisCustomViewBottom (Bool) - Determine whether renderCustomView is displayed before or after the text, image and video views; default is falseonPressMessage (Function(context, message)) - Callback when a message bubble is pressedonLongPressMessage (Function(context, message)) - Callback when a message bubble is long-pressed; you can use this to show action sheets (e.g., copy, delete, reply)imageProps (Object) - Extra props to be passed to the <Image> component created by the default renderMessageImageimageStyle (Object) - Custom style for message imagesvideoProps (Object) - Extra props to be passed to the video component created by the required renderMessageVideomessageTextProps (Object) - Extra props to be passed to the MessageText component. Useful for customizing link parsing behavior, text styles, and matchers. Supports the following props:matchers - Custom matchers for linking message content (like URLs, phone numbers, hashtags, mentions)linkStyle - Custom style for linksemail - Enable/disable email parsing (default: true)phone - Enable/disable phone number parsing (default: true)url - Enable/disable URL parsing (default: true)hashtag - Enable/disable hashtag parsing (default: false)mention - Enable/disable mention parsing (default: false)hashtagUrl - Base URL for hashtags (e.g., 'https://x.com/hashtag')mentionUrl - Base URL for mentions (e.g., 'https://x.com')stripPrefix - Strip 'http://' or 'https://' from URL display (default: false)TextComponent - Custom Text com