Building A Chat UI With Chat Bubbles In React JS
Hey guys! 👋 Ever wanted to build a chat interface in your React app, complete with those cool chat bubbles that make conversations feel so natural? You've come to the right place! In this article, we're going to dive deep into how to create a chat-like UI with chat bubbles in React JS. We'll be tackling the challenge of positioning these bubbles dynamically based on the sender, using Material UI for styling, Context API for state management, and JSX for structuring our components. Let's get started and make your chat interface dreams a reality!
Understanding the Basics
Before we jump into the code, let's break down the fundamental concepts we'll be using. React JS, a powerful JavaScript library for building user interfaces, will be our foundation. We'll use Material UI, a popular React UI framework, to make our chat bubbles look polished and professional. JSX, a syntax extension to JavaScript, will help us write our React components in a clear and concise way. The Context API will be crucial for managing our application's state, ensuring that our chat messages are accessible across different components. And finally, CSS will be our go-to tool for styling and positioning the chat bubbles.
Setting Up Your React Environment
First things first, you'll need to set up a React environment. If you're starting from scratch, Create React App is your best friend. It's a tool that sets up a new React project with all the modern build tools you need. To get started, open your terminal and run:
npx create-react-app chat-app
cd chat-app
npm start
This will create a new React project named "chat-app", navigate into the project directory, and start the development server. You should see your app running in your browser at http://localhost:3000
.
Installing Material UI
Next, let's install Material UI, our go-to library for beautiful and responsive components. Run the following command in your terminal:
npm install @mui/material @emotion/react @emotion/styled
This command installs Material UI's core library, along with Emotion, a CSS-in-JS library that Material UI uses for styling. With Material UI installed, we're ready to start building our chat interface.
Structuring Your Chat Interface with JSX
Now, let's dive into the heart of our project: structuring the chat interface with JSX. We'll create a few key components to manage our chat layout and message display. Imagine our chat interface as a container holding a list of messages. Each message will be displayed as a bubble, positioned either on the left or right side of the chat window, depending on who sent it. To achieve this, we'll need components for:
- ChatContainer: This component will act as the main container for our chat interface, holding the message list and input area.
- MessageList: This component will render the list of messages, mapping our message data to individual message components.
- MessageBubble: This component will represent a single chat bubble, displaying the message content and positioning it correctly based on the sender.
- MessageInput: This component will provide an input field and send button for users to type and send messages.
Creating the ChatContainer Component
Let's start by creating the ChatContainer
component. This component will be the main entry point for our chat interface. Create a new file named ChatContainer.js
in your src
directory and add the following code:
import React from 'react';
import MessageList from './MessageList';
import MessageInput from './MessageInput';
import { Container } from '@mui/material';
function ChatContainer() {
return (
<Container maxWidth="md">
<h1>React Chat UI</h1>
<MessageList />
<MessageInput />
</Container>
);
}
export default ChatContainer;
Here, we're importing the necessary components and Material UI's Container
component to provide a responsive layout. The ChatContainer
component renders a heading, the MessageList
component (which we'll create next), and the MessageInput
component (which we'll also create).
Building the MessageList Component
The MessageList
component is responsible for rendering the list of messages. It will receive an array of message objects and map them to individual MessageBubble
components. Create a new file named MessageList.js
in your src
directory and add the following code:
import React, { useContext } from 'react';
import MessageBubble from './MessageBubble';
import { ChatContext } from './ChatContext';
function MessageList() {
const { messages } = useContext(ChatContext);
return (
<div>
{messages.map((message) => (
<MessageBubble key={message.id} message={message} />
))}
</div>
);
}
export default MessageList;
In this component, we're using the useContext
hook to access the messages
array from our ChatContext
(which we'll set up later). We then map over the messages
array and render a MessageBubble
component for each message. Each MessageBubble
receives a message
prop containing the message object.
Crafting the MessageBubble Component
The MessageBubble
component is the star of the show. It's responsible for displaying a single chat bubble and positioning it on the left or right side based on the sender. Create a new file named MessageBubble.js
in your src
directory and add the following code:
import React from 'react';
import { Paper, Typography, Box } from '@mui/material';
function MessageBubble({ message }) {
const isCurrentUser = message.sender === 'currentUser';
return (
<Box
sx={{
display: 'flex',
justifyContent: isCurrentUser ? 'flex-end' : 'flex-start',
mb: 2,
}}
>
<Paper
sx={{
p: 1.5,
borderRadius: isCurrentUser ? '20px 0 20px 20px' : '0 20px 20px 20px',
bgcolor: isCurrentUser ? '#DCF8C6' : '#FFFFFF',
maxWidth: '80%',
}}
>
<Typography variant="body1">{message.text}</Typography>
</Paper>
</Box>
);
}
export default MessageBubble;
This component receives a message
prop and determines whether the message was sent by the current user. Based on this, it uses Material UI's Paper
and Typography
components to create a chat bubble with different styles and positioning. The isCurrentUser
variable is used to conditionally apply styles, ensuring that messages from the current user are displayed on the right and messages from others are displayed on the left.
Designing the MessageInput Component
Finally, let's create the MessageInput
component, which will provide an input field and send button for users to type and send messages. Create a new file named MessageInput.js
in your src
directory and add the following code:
import React, { useState, useContext } from 'react';
import { TextField, IconButton, InputAdornment } from '@mui/material';
import { Send as SendIcon } from '@mui/icons-material';
import { ChatContext } from './ChatContext';
function MessageInput() {
const [newMessage, setNewMessage] = useState('');
const { addMessage } = useContext(ChatContext);
const handleSendMessage = () => {
if (newMessage.trim() !== '') {
addMessage({
id: Date.now(),
text: newMessage,
sender: 'currentUser',
});
setNewMessage('');
}
};
return (
<TextField
fullWidth
variant="outlined"
placeholder="Type a message..."
value={newMessage}
onChange={(e) => setNewMessage(e.target.value)}
onKeyPress={(e) => {
if (e.key === 'Enter') {
handleSendMessage();
}
}}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<IconButton onClick={handleSendMessage}>
<SendIcon />
</IconButton>
</InputAdornment>
),
}}
/>
);
}
export default MessageInput;
This component uses Material UI's TextField
and IconButton
components to create an input field with a send button. It uses the useState
hook to manage the input value and the useContext
hook to access the addMessage
function from our ChatContext
(which we'll set up next). When the user types a message and presses Enter or clicks the send button, the handleSendMessage
function is called, which adds the new message to the chat.
Managing State with Context API
Now that we have our components in place, let's set up the Context API to manage our chat state. The Context API allows us to share state between components without having to pass props down manually at every level. This is perfect for our chat application, where we need to share the message list and add new messages from different components.
Creating the ChatContext
Create a new file named ChatContext.js
in your src
directory and add the following code:
import React, { createContext, useState } from 'react';
export const ChatContext = createContext();
export function ChatProvider({ children }) {
const [messages, setMessages] = useState([
{
id: 1,
text: 'Hey there! 👋',
sender: 'otherUser',
},
{
id: 2,
text: 'Hi! How can I help you?',
sender: 'currentUser',
},
]);
const addMessage = (message) => {
setMessages((prevMessages) => [...prevMessages, message]);
};
return (
<ChatContext.Provider value={{ messages, addMessage }}>
{children}
</ChatContext.Provider>
);
}
Here, we're creating a ChatContext
using createContext
. We're also creating a ChatProvider
component that will wrap our app and provide the chat state to its children. The ChatProvider
uses the useState
hook to manage the messages
array and provides an addMessage
function to add new messages to the list. We also have some dummy data here to initiate the chat.
Wrapping Your App with the ChatProvider
Now, let's wrap our app with the ChatProvider
to make the chat state available to all components. Open your src/index.js
file and modify it as follows:
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { ChatProvider } from './ChatContext';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<ChatProvider>
<App />
</ChatProvider>
</React.StrictMode>
);
We're importing the ChatProvider
and wrapping our App
component with it. This makes the messages
array and addMessage
function available to all components within our app.
Connecting Components to the ChatContext
With the ChatContext
set up, we can now connect our components to it. We've already done this in the MessageList
and MessageInput
components using the useContext
hook. These components can now access the messages
array and addMessage
function from the ChatContext
.
Styling Your Chat Bubbles with CSS and Material UI
Styling is key to making our chat bubbles look great. We've already used Material UI's styling capabilities within our MessageBubble
component to control the bubble's appearance and positioning. Let's recap how we did this and explore some additional styling options.
Conditional Styling
The most important aspect of styling our chat bubbles is the ability to conditionally apply styles based on the sender. We achieve this using the isCurrentUser
variable in the MessageBubble
component. This variable determines whether the message was sent by the current user and allows us to apply different styles accordingly.
For example, we use the isCurrentUser
variable to control the background color and border radius of the chat bubbles:
<Paper
sx={{
p: 1.5,
borderRadius: isCurrentUser ? '20px 0 20px 20px' : '0 20px 20px 20px',
bgcolor: isCurrentUser ? '#DCF8C6' : '#FFFFFF',
maxWidth: '80%',
}}
>
<Typography variant="body1">{message.text}</Typography>
</Paper>
Here, we're using the sx
prop, which is Material UI's way of applying styles using CSS-in-JS. We're setting the borderRadius
and bgcolor
based on the isCurrentUser
variable, creating the effect of messages from the current user appearing on the right with a green background and messages from others appearing on the left with a white background.
Additional Styling Options
Material UI provides a wide range of styling options that you can use to customize your chat bubbles further. You can control the padding, margin, font size, color, and many other aspects of the bubble's appearance.
For example, you can add a shadow to the bubbles to make them stand out more:
<Paper
sx={{
p: 1.5,
borderRadius: isCurrentUser ? '20px 0 20px 20px' : '0 20px 20px 20px',
bgcolor: isCurrentUser ? '#DCF8C6' : '#FFFFFF',
maxWidth: '80%',
boxShadow: '0px 3px 5px rgba(0, 0, 0, 0.2)',
}}
>
<Typography variant="body1">{message.text}</Typography>
</Paper>
Here, we're adding a boxShadow
property to the sx
object, which will add a subtle shadow to the chat bubbles.
Handling Dynamic Bubble Placement
The key to creating a chat-like UI is the dynamic placement of chat bubbles. We want messages from the current user to appear on the right and messages from others to appear on the left. We've already achieved this using the isCurrentUser
variable and conditional styling in the MessageBubble
component.
Flexbox for Positioning
We're using Flexbox to control the positioning of our chat bubbles. Flexbox is a powerful CSS layout module that makes it easy to align and distribute elements within a container. In our case, we're using Flexbox to align the chat bubbles to the left or right side of the chat window.
In the MessageBubble
component, we have the following code:
<Box
sx={{
display: 'flex',
justifyContent: isCurrentUser ? 'flex-end' : 'flex-start',
mb: 2,
}}
>
{/* ... */}
</Box>
Here, we're using a Box
component (which is a Material UI component that renders a div
with additional styling capabilities) with the sx
prop to apply Flexbox styles. We're setting the display
property to flex
to enable Flexbox layout. The justifyContent
property is used to control the horizontal alignment of the chat bubble. We're setting it to flex-end
if the message is from the current user (aligning the bubble to the right) and flex-start
if the message is from someone else (aligning the bubble to the left).
Ensuring Correct Bubble Order
To ensure that our chat bubbles are displayed in the correct order, we need to make sure that the messages are sorted chronologically. In our ChatContext
, we're simply adding new messages to the end of the messages
array. This ensures that the messages are displayed in the order they were sent.
Conclusion: Your Chat UI is Ready!
Woohoo! 🎉 You've successfully built a chat-like UI with chat bubbles in React JS! We've covered a lot of ground, from setting up your React environment and installing Material UI to structuring your components with JSX, managing state with the Context API, and styling your chat bubbles with CSS. You've learned how to dynamically position chat bubbles based on the sender and ensure that messages are displayed in the correct order.
Key Takeaways
- React JS is a powerful library for building user interfaces.
- Material UI provides beautiful and responsive components for your React apps.
- JSX makes it easy to structure your React components.
- The Context API is crucial for managing state in React applications.
- CSS and Flexbox are essential for styling and positioning elements.
Next Steps
Now that you have a basic chat UI, you can explore more advanced features, such as:
- Real-time messaging: Integrate a real-time messaging service like Socket.IO or Firebase to enable real-time communication.
- User authentication: Add user authentication to allow users to log in and send messages as themselves.
- Message history: Implement a system to store and retrieve message history.
- File uploads: Allow users to send files and images in the chat.
- Typing indicators: Display a typing indicator when a user is typing a message.
Keep experimenting and building, and you'll become a chat UI master in no time! Happy coding! 🚀