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:

  1. 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.

  2. 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.

  3. 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.

  4. 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) and sent (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 Views form the curved arrow shape – one for the main arrow (arrowStyles) and one for the overlapping part (arrowOverlapStyles).
  • 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 negative left or right values to extend it outside the bubble. The borderBottomLeftRadius and borderBottomRightRadius 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 an id, text content, and sent status.
  • We render a FlatList inside a SafeAreaView. The FlatList is a performant way to render lists in React Native.
  • We pass our MESSAGES array to the data prop and provide a renderItem function that returns a ChatBubble 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, and borderRadius values in the bubble style to change the bubble size and shape.
  • Tweak the arrow size and positioning by modifying the width, height, and borderBottomLeftRadius/borderBottomRightRadius values in the arrow styles.
  • Change the background colors in sentBubble, receivedBubble, sentArrow, and receivedArrow 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 the FlatList 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 with React.memo() to avoid unnecessary re-renders.

Alternative Approaches

While we‘ve built our chat bubble from scratch using basic Views 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 Views. 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!

Similar Posts