UNPKG

23.8 kBMarkdownView Raw
1<p align="center" >
2<p align="center" >
3 <a href="https://reactnative.gallery/FaridSafi/gifted-chat">
4    <img alt="react-native-gifted-chat" src="https://thumbs.gfycat.com/AbsoluteSadDobermanpinscher-size_restricted.gif" width="260" height="510" />
5 </a>
6
7</p>
8
9<h3 align="center">
10 💬 Gifted Chat
11</h3>
12<p align="center">
13 The most complete chat UI for React Native & Web
14</p>
15<p align="center">
16 <a href="https://www.npmjs.com/package/react-native-gifted-chat">
17 <img alt="npm downloads" src="https://img.shields.io/npm/dm/react-native-gifted-chat.svg"/></a>
18 <a href="https://www.npmjs.com/package/react-native-gifted-chat"><img alt="npm version" src="https://badge.fury.io/js/react-native-gifted-chat.svg"/></a>
19 <a href="https://greenkeeper.io/"><img src="https://badges.greenkeeper.io/FaridSafi/react-native-gifted-chat.svg" alt="build"></a>
20 <a href="https://reactnative.gallery/FaridSafi/gifted-chat"><img src="https://img.shields.io/badge/reactnative.gallery-%F0%9F%8E%AC-green.svg"/></a>
21
22</p>
23<p align="center">
24  <a href="https://circleci.com/gh/FaridSafi/react-native-gifted-chat"><img src="https://circleci.com/gh/FaridSafi/react-native-gifted-chat.svg?style=shield" alt="build"></a>
25  <a href="https://travis-ci.org/FaridSafi/react-native-gifted-chat"><img src="https://api.travis-ci.org/FaridSafi/react-native-gifted-chat.svg" alt="deployed"></a>
26 <a title='License' href="https://github.com/FaridSafi/react-native-gifted-chat/blob/master/LICENSE" height="18">
27 <img src='https://img.shields.io/badge/license-MIT-blue.svg' />
28 </a>
29 <a href="#hire-an-expert"><img src="https://img.shields.io/badge/%F0%9F%92%AA-hire%20an%20expert-brightgreen"/></a>
30</p>
31
32<p align="center">
33 <a href="https://reverent-bardeen-47c862.netlify.com/" target="_blank">Demo Web 🖥</a>
34</p>
35<p align="center">
36 <a href="https://snack.expo.io/@xcarpentier/giftedchat-playground" target="_blank">Snack GiftedChat playground</a>
37 <img height="18" src="https://snack.expo.io/favicon.ico" />
38</p>
39
40## Sponsor
41
42<p align="center">
43 <br/>
44 <a href="https://www.lereacteur.io" target="_blank">
45 <img src="https://raw.githubusercontent.com/FaridSafi/react-native-gifted-chat/master/media/logo_sponsor.png">
46 </a>
47 <br>
48 <p align="center">
49 Coding Bootcamp in Paris co-founded by Farid Safi
50 </p>
51 <a href="https://www.lereacteur.io" target="_blank">
52 <p align="center">
53 Click to learn more
54 </p>
55 </a>
56</p>
57
58<p align="center">
59 <br/>
60 <a href="https://getstream.io/chat/?utm_source=github&utm_medium=react-native-gifted-chat&utm_campaign=sponsorship" target="_blank">
61 <img src="https://i.imgur.com/oU7XYkk.png">
62 </a>
63 <br>
64 <p align="center">
65 Scalable <a href="https://getstream.io/chat/?utm_source=github&utm_medium=react-native-gifted-chat&utm_campaign=sponsorship" target="_blank">chat API/Server</a> written in Go
66 </p>
67 <p align="center">
68 <a href="https://getstream.io/chat/get_started/?utm_source=github&utm_medium=react-native-gifted-chat&utm_campaign=sponsorship" target="_blank">API Tour</a> | <a href="https://dev.to/nickparsons/react-native-chat-with-chuck-norris-3h7m?utm_source=github&utm_medium=react-native-gifted-chat&utm_campaign=sponsorship" target="_blank">React Native Gifted tutorial</a>
69 </p>
70</p>
71
72<p align="center">
73 <br/>
74 <a href="https://www.docdok.health/?utm_source=github&utm_medium=react-native-gifted-chat&utm_campaign=sponsorship" target="_blank">
75 <img src="https://www.dropbox.com/s/g4dcq267aqbykpz/logo.png?dl=0&raw=1">
76 </a>
77 <br>
78 <p align="center">Delivering Personalized Healthcare</p>
79 <p align="center">
80 <a href="https://www.docdok.health/?utm_source=github&utm_medium=react-native-gifted-chat&utm_campaign=sponsorship" target="_blank"> Find out more</a>
81 </p>
82</p>
83
84## Please vote
85
86**GiftedChat** depends on other packages and some needs a boost, please vote for PRs will improve it, thanks:
87
88- https://github.com/taskrabbit/react-native-parsed-text/pull/58
89- https://github.com/watadarkstar/react-native-typing-animation/issues/18
90
91## Features
92
93- 🎉 **_`react-native-web`able_ (since 0.10.0)** [web configuration](#react-native-web)
94- Write with **TypeScript** (since 0.8.0)
95- Fully customizable components
96- Composer actions (to attach photos, etc.)
97- Load earlier messages
98- Copy messages to clipboard
99- Touchable links using [react-native-parsed-text](https://github.com/taskrabbit/react-native-parsed-text)
100- Avatar as user's initials
101- Localized dates
102- Multi-line TextInput
103- InputToolbar avoiding keyboard
104- Redux support
105- System message
106- Quick Reply messages (bot)
107- Typying indicatior [react-native-typing-animation](https://github.com/watadarkstar/react-native-typing-animation)
108
109## Dependency
110
111- Use version `0.2.x` for RN `>= 0.44.0`
112- Use version `0.1.x` for RN `>= 0.40.0`
113- Use version `0.0.10` for RN `< 0.40.0`
114
115## Installation
116
117- Using [npm](https://www.npmjs.com/#getting-started): `npm install react-native-gifted-chat --save`
118- Using [Yarn](https://yarnpkg.com/): `yarn add react-native-gifted-chat`
119
120### react-native-video and expo-av
121
122- Both dependencies are removed since `0.11.0`.
123- You still be able to provide a `video` but you need to provide `renderMessageVideo` prop.
124
125## You have a question?
126
1271. Please check this readme and may find a response
1281. Please ask on StackOverflow first: https://stackoverflow.com/questions/tagged/react-native-gifted-chat
1291. Find response on existing issues
1301. Try to keep issues for issues
131
132## Example
133
134```jsx
135import React, { useState, useCallback, useEffect } from 'react'
136import { GiftedChat } from 'react-native-gifted-chat'
137
138export function Example() {
139 const [messages, setMessages] = useState([]);
140
141 useEffect(() => {
142 setMessages([
143 {
144 _id: 1,
145 text: 'Hello developer',
146 createdAt: new Date(),
147 user: {
148 _id: 2,
149 name: 'React Native',
150 avatar: 'https://placeimg.com/140/140/any',
151 },
152 },
153 ])
154 }, [])
155
156 const onSend = useCallback((messages = []) => {
157 setMessages(previousMessages => GiftedChat.append(previousMessages, messages))
158 }, [])
159
160 return (
161 <GiftedChat
162 messages={messages}
163 onSend={messages => onSend(messages)}
164 user={{
165 _id: 1,
166 }}
167 />
168 )
169}
170```
171
172## Advanced example
173
174See [`App.tsx`](https://github.com/FaridSafi/react-native-gifted-chat/blob/master/App.tsx) for a working demo!
175
176## "Slack" example
177
178See the files in [`example-slack-message`](example-slack-message) for an example of how to override the default UI to make something that looks more like Slack -- with usernames displayed and all messages on the left.
179
180## Message object
181
182> e.g. Chat Message
183
184```ts
185export interface IMessage {
186 _id: string | number
187 text: string
188 createdAt: Date | number
189 user: User
190 image?: string
191 video?: string
192 audio?: string
193 system?: boolean
194 sent?: boolean
195 received?: boolean
196 pending?: boolean
197 quickReplies?: QuickReplies
198}
199```
200
201```js
202{
203 _id: 1,
204 text: 'My message',
205 createdAt: new Date(Date.UTC(2016, 5, 11, 17, 20, 0)),
206 user: {
207 _id: 2,
208 name: 'React Native',
209 avatar: 'https://facebook.github.io/react/img/logo_og.png',
210 },
211 image: 'https://facebook.github.io/react/img/logo_og.png',
212 // You can also add a video prop:
213 video: 'http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4',
214 // Mark the message as sent, using one tick
215 sent: true,
216 // Mark the message as received, using two tick
217 received: true,
218 // Mark the message as pending with a clock loader
219 pending: true,
220 // Any additional custom parameters are passed through
221}
222```
223
224> e.g. System Message
225
226```js
227{
228 _id: 1,
229 text: 'This is a system message',
230 createdAt: new Date(Date.UTC(2016, 5, 11, 17, 20, 0)),
231 system: true,
232 // Any additional custom parameters are passed through
233}
234```
235
236> e.g. Chat Message with Quick Reply options
237
238See PR [#1211](https://github.com/FaridSafi/react-native-gifted-chat/pull/1211)
239
240```ts
241interface Reply {
242 title: string
243 value: string
244 messageId?: any
245}
246
247interface QuickReplies {
248 type: 'radio' | 'checkbox'
249 values: Reply[]
250 keepIt?: boolean
251}
252```
253
254```js
255 {
256 _id: 1,
257 text: 'This is a quick reply. Do you love Gifted Chat? (radio) KEEP IT',
258 createdAt: new Date(),
259 quickReplies: {
260 type: 'radio', // or 'checkbox',
261 keepIt: true,
262 values: [
263 {
264 title: '😋 Yes',
265 value: 'yes',
266 },
267 {
268 title: '📷 Yes, let me show you with a picture!',
269 value: 'yes_picture',
270 },
271 {
272 title: '😞 Nope. What?',
273 value: 'no',
274 },
275 ],
276 },
277 user: {
278 _id: 2,
279 name: 'React Native',
280 },
281 },
282 {
283 _id: 2,
284 text: 'This is a quick reply. Do you love Gifted Chat? (checkbox)',
285 createdAt: new Date(),
286 quickReplies: {
287 type: 'checkbox', // or 'radio',
288 values: [
289 {
290 title: 'Yes',
291 value: 'yes',
292 },
293 {
294 title: 'Yes, let me show you with a picture!',
295 value: 'yes_picture',
296 },
297 {
298 title: 'Nope. What?',
299 value: 'no',
300 },
301 ],
302 },
303 user: {
304 _id: 2,
305 name: 'React Native',
306 },
307 }
308```
309
310## Props
311
312- **`messages`** _(Array)_ - Messages to display
313- **`isTyping`** _(Bool)_ - Typing Indicator state; default `false`. If you use`renderFooter` it will override this.
314- **`text`** _(String)_ - Input text; default is `undefined`, but if specified, it will override GiftedChat's internal state (e.g. for redux; [see notes below](#notes-for-redux))
315- **`placeholder`** _(String)_ - Placeholder when `text` is empty; default is `'Type a message...'`
316- **`messageIdGenerator`** _(Function)_ - Generate an id for new messages. Defaults to UUID v4, generated by [uuid](https://github.com/kelektiv/node-uuid)
317- **`user`** _(Object)_ - User sending the messages: `{ _id, name, avatar }`
318- **`onSend`** _(Function)_ - Callback when sending a message
319- **`alwaysShowSend`** _(Bool)_ - Always show send button in input text composer; default `false`, show only when text input is not empty
320- **`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'`)
321- **`timeFormat`** _(String)_ - Format to use for rendering times; default is `'LT'`
322- **`dateFormat`** _(String)_ - Format to use for rendering dates; default is `'ll'`
323- **`loadEarlier`** _(Bool)_ - Enables the "load earlier messages" button, required for `infiniteScroll`
324- **`isKeyboardInternallyHandled`** _(Bool)_ - Determine whether to handle keyboard awareness inside the plugin. If you have your own keyboard handling outside the plugin set this to false; default is `true`
325- **`onLoadEarlier`** _(Function)_ - Callback when loading earlier messages
326- **`isLoadingEarlier`** _(Bool)_ - Display an `ActivityIndicator` when loading earlier messages
327- **`renderLoading`** _(Function)_ - Render a loading view when initializing
328- **`renderLoadEarlier`** _(Function)_ - Custom "Load earlier messages" button
329- **`renderAvatar`** _(Function)_ - Custom message avatar; set to `null` to not render any avatar for the message
330- **`showUserAvatar`** _(Bool)_ - Whether to render an avatar for the current user; default is `false`, only show avatars for other users
331- **`showAvatarForEveryMessage`** _(Bool)_ - When false, avatars will only be displayed when a consecutive message is from the same user on the same day; default is `false`
332- **`onPressAvatar`** _(Function(`user`))_ - Callback when a message avatar is tapped
333- **`onLongPressAvatar`** _(Function(`user`))_ - Callback when a message avatar is long-pressed
334- **`renderAvatarOnTop`** _(Bool)_ - Render the message avatar at the top of consecutive messages, rather than the bottom; default is `false`
335- **`renderBubble`** _(Function)_ - Custom message bubble
336- **`renderTicks`** _(Function(`message`))_ - Custom ticks indicator to display message status
337- **`renderSystemMessage`** _(Function)_ - Custom system message
338- **`onLongPress`** _(Function(`context`, `message`))_ - Callback when a message bubble is long-pressed; default is to show an ActionSheet with "Copy Text" (see [example using `showActionSheetWithOptions()`](https://github.com/FaridSafi/react-native-gifted-chat/blob/master@%7B2017-09-25%7D/src/Bubble.js#L96-L119))
339- **`inverted`** _(Bool)_ - Reverses display order of `messages`; default is `true`
340- **`renderUsernameOnMessage`** _(Bool)_ - Indicate whether to show the user's username inside the message bubble; default is `false`
341- **`renderMessage`** _(Function)_ - Custom message container
342- **`renderMessageText`** _(Function)_ - Custom message text
343- **`renderMessageImage`** _(Function)_ - Custom message image
344- **`renderMessageVideo`** _(Function)_ - Custom message video
345- **`imageProps`** _(Object)_ - Extra props to be passed to the [`<Image>`](https://facebook.github.io/react-native/docs/image.html) component created by the default `renderMessageImage`
346- **`videoProps`** _(Object)_ - Extra props to be passed to the video component created by the required `renderMessageVideo`
347- **`lightboxProps`** _(Object)_ - Extra props to be passed to the `MessageImage`'s [Lightbox](https://github.com/oblador/react-native-lightbox)
348- **`isCustomViewBottom`** _(Bool)_ - Determine whether renderCustomView is displayed before or after the text, image and video views; default is `false`
349- **`renderCustomView`** _(Function)_ - Custom view inside the bubble
350- **`renderDay`** _(Function)_ - Custom day above a message
351- **`renderTime`** _(Function)_ - Custom time inside a message
352- **`renderFooter`** _(Function)_ - Custom footer component on the ListView, e.g. `'User is typing...'`; see [example/App.js](example/App.js) for an example. Overrides default typing indicator that triggers when `isTyping` is true.
353- **`renderChatEmpty`** _(Function)_ - Custom component to render in the ListView when messages are empty
354- **`renderChatFooter`** _(Function)_ - Custom component to render below the MessageContainer (separate from the ListView)
355- **`renderInputToolbar`** _(Function)_ - Custom message composer container
356- **`renderComposer`** _(Function)_ - Custom text input message composer
357- **`renderActions`** _(Function)_ - Custom action button on the left of the message composer
358- **`renderSend`** _(Function)_ - Custom send button; you can pass children to the original `Send` component quite easily, for example, to use a custom icon ([example](https://github.com/FaridSafi/react-native-gifted-chat/pull/487))
359- **`renderAccessory`** _(Function)_ - Custom second line of actions below the message composer
360- **`onPressActionButton`** _(Function)_ - Callback when the Action button is pressed (if set, the default `actionSheet` will not be used)
361- **`bottomOffset`** _(Integer)_ - Distance of the chat from the bottom of the screen (e.g. useful if you display a tab bar)
362- **`minInputToolbarHeight`** _(Integer)_ - Minimum height of the input toolbar; default is `44`
363- **`listViewProps`** _(Object)_ - Extra props to be passed to the messages [`<ListView>`](https://facebook.github.io/react-native/docs/listview.html); some props can't be overridden, see the code in `MessageContainer.render()` for details
364- **`textInputProps`** _(Object)_ - Extra props to be passed to the [`<TextInput>`](https://facebook.github.io/react-native/docs/textinput.html)
365- **`textInputStyle`** _(Object)_ - Custom style to be passed to the [`<TextInput>`](https://facebook.github.io/react-native/docs/textinput.html)
366- **`multiline`** _(Bool)_ - Indicates whether to allow the [`<TextInput>`](https://facebook.github.io/react-native/docs/textinput.html) to be multiple lines or not; default `true`.
367- **`keyboardShouldPersistTaps`** _(Enum)_ - Determines whether the keyboard should stay visible after a tap; see [`<ScrollView>`](https://facebook.github.io/react-native/docs/scrollview.html) docs
368- **`onInputTextChanged`** _(Function)_ - Callback when the input text changes
369- **`maxInputLength`** _(Integer)_ - Max message composer TextInput length
370- **`parsePatterns`** _(Function)_ - Custom parse patterns for [react-native-parsed-text](https://github.com/taskrabbit/react-native-parsed-text) used to linking message content (like URLs and phone numbers), e.g.:
371
372```js
373 <GiftedChat
374 parsePatterns={(linkStyle) => [
375 { type: 'phone', style: linkStyle, onPress: this.onPressPhoneNumber },
376 { pattern: /#(\w+)/, style: { ...linkStyle, styles.hashtag }, onPress: this.onPressHashtag },
377 ]}
378 />
379```
380
381- **`extraData`** _(Object)_ - Extra props for re-rendering FlatList on demand. This will be useful for rendering footer etc.
382- **`minComposerHeight`** _(Object)_ - Custom min-height of the composer.
383- **`maxComposerHeight`** _(Object)_ - Custom max height of the composer.
384
385* **`scrollToBottom`** _(Bool)_ - Enables the scroll to bottom Component (Default is false)
386* **`scrollToBottomComponent`** _(Function)_ - Custom Scroll To Bottom Component container
387* **`scrollToBottomOffset`** _(Integer)_ - Custom Height Offset upon which to begin showing Scroll To Bottom Component (Default is 200)
388* **`scrollToBottomStyle`** _(Object)_ - Custom style for Bottom Component container
389* **`alignTop`** _(Boolean)_ Controls whether or not the message bubbles appear at the top of the chat (Default is false - bubbles align to bottom)
390* **`onQuickReply`** _(Function)_ - Callback when sending a quick reply (to backend server)
391* **`renderQuickReplies`** _(Function)_ - Custom all quick reply view
392* **`quickReplyStyle`** _(StyleProp<ViewStyle>)_ - Custom quick reply view style
393* **`renderQuickReplySend`** _(Function)_ - Custom quick reply **send** view
394* **`shouldUpdateMessage`** _(Function)_ - Lets the message component know when to update outside of normal cases.
395* **`infiniteScroll`** _(Bool)_ - infinite scroll up when reach the top of messages container, automatically call onLoadEarlier function if exist (not yet supported for the web). You need to add `loadEarlier` prop too.
396
397## Imperative methods
398
399- `focusTextInput()` - Open the keyboard and focus the text input box
400
401## Notes for [Redux](https://github.com/reactjs/redux)
402
403The `messages` prop should work out-of-the-box with Redux. In most cases, this is all you need.
404
405If you decide to specify a `text` prop, GiftedChat will no longer manage its own internal `text` state and will defer entirely to your prop.
406This is great for using a tool like Redux, but there's one extra step you'll need to take:
407simply implement `onInputTextChanged` to receive typing events and reset events (e.g. to clear the text `onSend`):
408
409```js
410<GiftedChat
411 text={customText}
412 onInputTextChanged={text => this.setCustomText(text)}
413 /* ... */
414/>
415```
416
417## Notes for Android
418
419If you are using Create React Native App / Expo, no Android specific installation steps are required -- you can skip this section. Otherwise, we recommend modifying your project configuration as follows.
420
421- Make sure you have `android:windowSoftInputMode="adjustResize"` in your `AndroidManifest.xml`:
422
423 ```xml
424 <activity
425 android:name=".MainActivity"
426 android:label="@string/app_name"
427 android:windowSoftInputMode="adjustResize"
428 android:configChanges="keyboard|keyboardHidden|orientation|screenSize">
429 ```
430
431- For **Expo**, there are at least 2 solutions to fix it:
432
433 - Append [`KeyboardAvoidingView`](https://facebook.github.io/react-native/docs/keyboardavoidingview) after GiftedChat. This should only be done for Android, as `KeyboardAvoidingView` may conflict with the iOS keyboard avoidance already built into GiftedChat, e.g.:
434
435```
436<View style={{ flex: 1 }}>
437 <GiftedChat />
438 {
439 Platform.OS === 'android' && <KeyboardAvoidingView behavior="padding" />
440 }
441</View>
442```
443
444If you use React Navigation, additional handling may be required to account for navigation headers and tabs. `KeyboardAvoidingView`'s `keyboardVerticalOffset` property can be set to the height of the navigation header and [`tabBarOptions.keyboardHidesTabBar`](https://reactnavigation.org/docs/en/bottom-tab-navigator.html#bottomtabnavigatorconfig) can be set to keep the tab bar from being shown when the keyboard is up. Due to a [bug with calculating height on Android phones with notches](facebook/react-native#23693), `KeyboardAvoidingView` is recommended over other solutions that involve calculating the height of the window.
445
446- adding an opaque background status bar on app.json (even though `android:windowSoftInputMode="adjustResize"` is set internally on Expo's Android apps, the translucent status bar causes it not to work): https://docs.expo.io/versions/latest/guides/configuration.html#androidstatusbar
447
448- If you plan to use `GiftedChat` inside a `Modal`, see [#200](https://github.com/FaridSafi/react-native-gifted-chat/issues/200).
449
450## Notes for local development
451
452### Native
453
4541. Install `yarn add -g expo-cli`
4552. `expo start`
456
457### react-native-web
458
459#### With expo
460
4611. Install `yarn add -g expo-cli`
4622. `expo start -w`
463
464[Upgrade snack version](https://snackager.expo.io/bundle/react-native-gifted-chat@0.15.0?bypassCache=true)
465
466#### With create-react-app
467
4681. `yarn add -D react-app-rewired`
4692. `touch config-overrides.js`
470
471```js
472module.exports = function override(config, env) {
473 config.module.rules.push({
474 test: /\.js$/,
475 exclude: /node_modules[/\\](?!react-native-gifted-chat|react-native-lightbox|react-native-parsed-text)/,
476 use: {
477 loader: 'babel-loader',
478 options: {
479 babelrc: false,
480 configFile: false,
481 presets: [
482 ['@babel/preset-env', { useBuiltIns: 'usage' }],
483 '@babel/preset-react',
484 ],
485 plugins: ['@babel/plugin-proposal-class-properties'],
486 },
487 },
488 })
489
490 return config
491}
492```
493
494> You will find an example and a **web demo** here: [xcarpentier/gifted-chat-web-demo](https://github.com/xcarpentier/gifted-chat-web-demo)
495
496> Another example with **Gatsby** : [xcarpentier/clean-archi-boilerplate](https://github.com/xcarpentier/clean-archi-boilerplate/tree/develop/apps/web)
497
498## Questions
499
500- [How can I set Bubble color for each user?](https://github.com/FaridSafi/react-native-gifted-chat/issues/672)
501- [How can I pass style props to InputToolbar design and customize its color and other styles properties?](https://github.com/FaridSafi/react-native-gifted-chat/issues/662)
502- [How can I change the color of the message box?](https://github.com/FaridSafi/react-native-gifted-chat/issues/640)
503- [Is there a way to manually dismiss the keyboard?](https://github.com/FaridSafi/react-native-gifted-chat/issues/647)
504- [I want to implement a popover that pops right after clicking on a specific avatar,
505 what is the best implementation in this case and how?](https://github.com/FaridSafi/react-native-gifted-chat/issues/660)
506- [Why TextInput is hidden on Android?](https://github.com/FaridSafi/react-native-gifted-chat/issues/680#issuecomment-359699364)
507- [How to use renderLoading?](https://github.com/FaridSafi/react-native-gifted-chat/issues/298)
508- [Can I use MySql to save the message?](https://github.com/FaridSafi/react-native-gifted-chat/issues/738)
509
510## License
511
512- [MIT](LICENSE)
513
514## Author
515
516Feel free to ask me questions on Twitter [@FaridSafi](https://www.twitter.com/FaridSafi)! or [@xcapetir](https://www.twitter.com/xcapetir)!
517
518## Contributors
519
520- Kevin Cooper [cooperka](https://github.com/cooperka)
521- Kfir Golan [kfiroo](https://github.com/kfiroo)
522- Bruno Cascio [brunocascio](https://github.com/brunocascio)
523- Xavier Carpentier [xcarpentier](https://github.com/xcarpentier)
524- [more](https://github.com/FaridSafi/react-native-gifted-chat/graphs/contributors)
525
526## Hire an expert!
527
528Looking for a ReactNative freelance expert with more than 12 years of experience? Contact Xavier from his [website](https://xaviercarpentier.com)!