How to Design an iMessage-like Chat Bubble in React Native
If you‘re building a chat or messaging interface in React Native, you‘ve probably considered how to make your chat bubbles look polished and modern. Many apps these days take inspiration from the sleek design of iMessage, with its rounded shapes, curved arrow, and contrasting color scheme for sent and received messages.
In this guide, we‘ll walk through how to create an iMessage-style chat bubble from scratch in React Native. By the end, you‘ll have a reusable chat bubble component you can drop into your own app. Let‘s get started!
Anatomy of the iMessage Chat Bubble
Before we dive into code, let‘s break down the key elements of the iMessage chat bubble design:
-
Rounded rectangle shape: The chat bubble has rounded corners, giving it a softer look compared to sharp edges. The amount of corner rounding is relatively subtle.
-
Curved arrow: A curved arrow juts out from the chat bubble on either the left or right side, depending on whether the message was sent or received. This arrow helps visually anchor the chat bubble and provides a clear direction.
-
Color scheme: iMessage uses a blue background for sent messages and a light gray background for received messages. The text inside the bubble is white for sent messages and black for received messages, ensuring good contrast.
-
Dynamic width: The width of the chat bubble expands to fit the message content. Longer messages produce wider bubbles, but there is a maximum width after which the text wraps.
With these elements in mind, let‘s look at how to build this design in React Native.
Setting Up a React Native Project
First, make sure you have React Native set up on your machine. If you haven‘t done this before, follow the official Getting Started guide for React Native.
Create a new React Native project:
npx react-native init ChatBubbleExample
cd ChatBubbleExample
Creating the Chat Bubble Component
Let‘s create a reusable ChatBubble
component that we can use for both sent and received messages. Create a new file called ChatBubble.js
:
import React from ‘react‘;
import { View, Text, StyleSheet } from ‘react-native‘;
const ChatBubble = ({ text, sent }) => {
const bubbleStyles = [
styles.bubble,
sent ? styles.sentBubble : styles.receivedBubble,
];
const textStyles = [
styles.text,
sent ? styles.sentText : styles.receivedText,
];
const arrowStyles = sent ? styles.sentArrow : styles.receivedArrow;
const arrowOverlapStyles = sent ? styles.sentArrowOverlap : styles.receivedArrowOverlap;
return (
<View style={bubbleStyles}>
<View style={arrowStyles} />
<View style={arrowOverlapStyles} />
<Text style={textStyles}>{text}</Text>
</View>
);
};
const styles = StyleSheet.create({
bubble: {
maxWidth: ‘75%‘,
paddingHorizontal: 12,
paddingVertical: 8,
borderRadius: 20,
},
sentBubble: {
alignSelf: ‘flex-end‘,
backgroundColor: ‘#0084ff‘,
marginRight: 8,
},
receivedBubble: {
alignSelf: ‘flex-start‘,
backgroundColor: ‘#e5e5ea‘,
marginLeft: 8,
},
text: {
fontSize: 16,
},
sentText: {
color: ‘white‘,
},
receivedText: {
color: ‘black‘,
},
sentArrow: {
backgroundColor: ‘#0084ff‘,
position: ‘absolute‘,
right: -6,
bottom: 0,
width: 20,
height: 20,
borderBottomLeftRadius: 16,
},
receivedArrow: {
backgroundColor: ‘#e5e5ea‘,
position: ‘absolute‘,
left: -6,
bottom: 0,
width: 20,
height: 20,
borderBottomRightRadius: 16,
},
sentArrowOverlap: {
backgroundColor: ‘white‘,
position: ‘absolute‘,
right: -20,
bottom: -4,
width: 20,
height: 20,
borderBottomLeftRadius: 12,
},
receivedArrowOverlap: {
backgroundColor: ‘white‘,
position: ‘absolute‘,
left: -20,
bottom: -4,
width: 20,
height: 20,
borderBottomRightRadius: 12,
},
});
export default ChatBubble;
Let‘s break this down:
- The
ChatBubble
component accepts two props:text
(the message content) andsent
(a boolean indicating whether the message was sent or received). - We define different styles for sent and received bubbles and apply them conditionally based on the
sent
prop. This includes the background color, alignment (sent bubbles align to the right, received to the left), and margin. - The chat bubble consists of three nested
View
components:- The outer
View
is the main bubble shape with rounded corners. - Two inner
View
s form the curved arrow shape – one for the main arrow (arrowStyles
) and one for the overlapping part (arrowOverlapStyles
).
- The outer
- The
Text
component inside the bubble displays the actual message content. - We use
StyleSheet.create()
to define reusable styles. The arrow styles are the trickiest part – we position the arrow absolutely at the bottom corner of the bubble and use negativeleft
orright
values to extend it outside the bubble. TheborderBottomLeftRadius
andborderBottomRightRadius
properties create the curved shape.
Using the Chat Bubble Component
Now let‘s use our ChatBubble
component to render a list of messages. In your App.js
file:
import React from ‘react‘;
import { SafeAreaView, FlatList, StyleSheet } from ‘react-native‘;
import ChatBubble from ‘./ChatBubble‘;
const MESSAGES = [
{ id: ‘1‘, text: ‘Hey there!‘, sent: true },
{ id: ‘2‘, text: ‘How are you doing?‘, sent: false },
{ id: ‘3‘, text: ‘I\‘m great, thanks for asking!‘, sent: true },
// ...
];
const App = () => {
return (
<SafeAreaView style={styles.container}>
<FlatList
data={MESSAGES}
renderItem={({ item }) => (
<ChatBubble text={item.text} sent={item.sent} />
)}
keyExtractor={item => item.id}
contentContainerStyle={styles.messageList}
inverted
/>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: ‘white‘,
},
messageList: {
paddingHorizontal: 8,
},
});
export default App;
Here‘s what we‘re doing:
- We define a
MESSAGES
array to simulate a list of messages. Each message has anid
,text
content, andsent
status. - We render a
FlatList
inside aSafeAreaView
. TheFlatList
is a performant way to render lists in React Native. - We pass our
MESSAGES
array to thedata
prop and provide arenderItem
function that returns aChatBubble
component for each message. - The
inverted
prop flips the order of the messages so the most recent ones appear at the bottom.
And that‘s it! You should now see a list of alternating blue and gray chat bubbles:
[Insert screenshot of chat bubbles in emulator]Further Customization
There are many ways you can customize the chat bubble design:
- Adjust the
paddingHorizontal
,paddingVertical
, andborderRadius
values in thebubble
style to change the bubble size and shape. - Tweak the arrow size and positioning by modifying the
width
,height
, andborderBottomLeftRadius
/borderBottomRightRadius
values in the arrow styles. - Change the background colors in
sentBubble
,receivedBubble
,sentArrow
, andreceivedArrow
to match your app‘s color scheme. - Customize the
text
style to change the font, size, or color of the message text.
You can also add additional elements inside the ChatBubble
component, such as a timestamp, sender name, or message status indicator.
Optimizing Performance
As your message list grows, there are a few things you can do to optimize performance:
- Use
getItemLayout
on theFlatList
to provide the exact dimensions of each item and enable more efficient rendering. - Implement pagination or lazy loading to fetch messages in smaller batches as the user scrolls.
- Memoize the
ChatBubble
component withReact.memo()
to avoid unnecessary re-renders.
Alternative Approaches
While we‘ve built our chat bubble from scratch using basic View
s and styles, there are alternative approaches and third-party libraries you can consider:
- Use an SVG path for the chat bubble shape instead of nesting
View
s. This can simplify the component structure and allow for more flexible customization. - Check out libraries like react-native-gifted-chat or react-native-easy-chat-ui that provide pre-built chat UI components you can customize.
Conclusion
In this guide, we‘ve walked through how to create an iMessage-style chat bubble component in React Native. By breaking down the design into its key elements and implementing them step by step, we‘ve achieved a polished and modern look that you can easily integrate into your own chat or messaging app.
Remember to experiment with different styles and layout options to find the perfect fit for your app‘s design. And don‘t forget to optimize performance as your message list grows.
I hope this guide has been helpful! Feel free to reach out with any questions or suggestions. Happy coding!