Creating a real-time chat application may seem difficult for beginners, but it becomes easy with React JS and tools like ChatEngine.io. So in this article, we will create a real-time chat application using ChatEngine.io so that it will be easy for you to create this project.
In this project, we will explain the complete step-by-step process from start to finish, you have to follow all the steps carefully so that in the end, you will have a fully functional chat app ready to use.
So let's get started.
Table of contents:
- Prerequisites
- Setting Up Your ChatEngine.io Account and Obtaining Your Project ID
- Adding Users to Your Chat Application
- Starting Your Project
- Creating Essential Files in Your Project
- Developing Your Components
- Integrating ChatEngine into Your Application
- Styling Your Project
- Running Your Application
- Adding Users and Setting Up Group Chats
- Advanced Customization Options
- Deploying Your Application
Prerequisites
Before you begin, ensure you have the following:
- Basic knowledge of React JS.
- Node.js and npm are installed on your system.
Setting Up Your ChatEngine.io Account and Obtaining Your Project ID
- Visit the official ChatEngine.io website and click on "Sign Up" to create an account.
- After signing up, navigate to "My Project" and click on "New Project".
- Fill the project title and promo code, then click "Create Project." You will be redirected to the project settings page and in the center of the page you will find your "Project ID". Remember to write down your "Project ID". You'll need it later for your application in the App.js file.
Adding Users to Your Chat Application
Create Users:
In the ChatEngine.io "My Project", go to "Users" in the left sidebar. Click on the "New User" option and fill in the required details (username, password, email, etc.). Click "Create person".
Create Chats:
Navigate to "Chats" below the "Users" option. Click on "New Chat" and fill in the Chat title, Admin Username (use the same Admin Username you created before), and the Access Key (password). Then, click on the "Create Chat" button.
Important: If you're unsure why these steps matter in the project, don't worry. They're all part of the process we need to finish the project successfully. Just follow along and keep these tabs open in your browser. Once the project is done, you'll see firsthand why each step was important.
Now, let's start building the project from the beginning.
Starting Your Project
Create a new file, open it in the VS Code editor, then execute the following command in the terminal.
npx create-react-app .
In your "src" folder, keep only App.css, index.js, and App.js files and remove all other files. In the "public" folder, keep only index.html and delete all other files. It's not required, but it's a sign of a professional developer to keep your project's structure organized.
To start the project from scratch, delete all codes inside the App.css file, remove some code from the index.js file, and remove all codes in the App.js file. Then, replace the code in both the App.js and index.js files with the new code provided.
// index.js file
import React from "react";
import ReactDOM from 'react-dom/client'
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<App />
);
// App.js file
import React from 'react'
function App() {
return (
<div>App</div>
)
}
export default App;
After completing these steps, your project structure, App.js, and index.js files should appear like this.
Install the necessary dependencies for ChatEngine, Ant Design, and Axios by running the following commands in your terminal:
npm install axios react-chat-engine @ant-design/icons
Make sure this tool is installed correctly in your project. You can check this by opening the package.json file and checking under "dependencies" to see if it's listed there.
Creating Essential Files in Your Project
Create a new "components " folder inside the "src" folder.
Inside the "components" folder, create the following files:
- ChatFeed.jsx
- MessageForm.jsx
- MyMessage.jsx
- TheirMessage.jsx
- LoginForm.jsx
- LogoutButton.jsx
Developing Your Components
In the ChatFeed.jsx file, we will create the chat interface of the messaging app. It will display the chat messages, show read receipts, and render the message form for sending new messages.
// src\components\ChatFeed.jsx
import MyMessage from './MyMessage';
import TheirMessage from './TheirMessage';
import MessageForm from './MessageForm';
const ChatFeed = (props) => {
const { chats, activeChat, userName, messages } = props;
const chat = chats && chats[activeChat];
const renderReadReceipts = (message, isMyMessage) => chat.people.map((person, index) => person.last_read === message.id && (
<div
key={`read_${index}`}
className="read-receipt"
style={{
float: isMyMessage ? 'right' : 'left',
backgroundImage: person.person.avatar && `url(${person.person.avatar})`,
}}
/>
));
const renderMessages = () => {
const keys = Object.keys(messages);
return keys.map((key, index) => {
const message = messages[key];
const lastMessageKey = index === 0 ? null : keys[index - 1];
const isMyMessage = userName === message.sender.username;
return (
<div key={`msg_${index}`} style={{ width: '100%' }}>
<div className="message-block">
{isMyMessage
? <MyMessage message={message} />
: <TheirMessage message={message} lastMessage={messages[lastMessageKey]} />}
</div>
<div className="read-receipts" style={{ marginRight: isMyMessage ? '20px' : '0px', marginLeft: isMyMessage ? '0px' : '66px' }}>
{renderReadReceipts(message, isMyMessage)}
</div>
</div>
);
});
};
if (!chat) return <div />;
return (
<div className="chat-feed">
<div className="chat-title-container">
<div className="chat-title">{chat?.title}</div>
<div className="chat-subtitle">
{chat.people.map((person) => ` ${person.person.username}`)}
</div>
</div>
{renderMessages()}
<div style={{ height: '100px' }} />
<div className="message-form-container">
<MessageForm {...props} chatId={activeChat} />
</div>
</div>
);
};
export default ChatFeed;
The ChatFeed component in a React chat application displays the chat interface by importing and using MyMessage, TheirMessage, and MessageForm components. It receives props like chats, activeChat, userName, and messages.
It includes key functions: renderReadReceipts to show who has read the messages and renderMessages to display all chat messages appropriately based on whether they are sent by the current user or others. If there's no active chat, it returns an empty <div />. Otherwise, it shows the chat title, participants, messages, and a message input form, making the chat interface interactive and user-friendly.
In the MessageForm.jsx file, we will create the message input form for the chat app. This form will allow users to type and send messages, show typing indicators, and upload images.
// src\components\MessageForm.jsx
import { useState } from 'react';
import { SendOutlined, PictureOutlined } from '@ant-design/icons';
import { sendMessage, isTyping } from 'react-chat-engine';
const MessageForm = (props) => {
const [value, setValue] = useState('');
const { chatId, creds } = props;
const handleChange = (event) => {
setValue(event.target.value);
isTyping(props, chatId);
};
const handleSubmit = (event) => {
event.preventDefault();
const text = value.trim();
if (text.length > 0) {
sendMessage(creds, chatId, { text });
}
setValue('');
};
const handleUpload = (event) => {
sendMessage(creds, chatId, { files: event.target.files, text: '' });
};
return (
<form className="message-form" onSubmit={handleSubmit}>
<input
className="message-input"
placeholder="Send a message..."
value={value}
onChange={handleChange}
onSubmit={handleSubmit}
/>
<label htmlFor="upload-button">
<span className="image-button">
<PictureOutlined className="picture-icon" />
</span>
</label>
<input
type="file"
multiple={false}
id="upload-button"
style={{ display: 'none' }}
onChange={handleUpload.bind(this)}
/>
<button type="submit" className="send-button">
<SendOutlined className="send-icon" />
</button>
</form>
);
};
export default MessageForm;
The MessageForm component in a React chat app allows users to send text and images. It manages input with a useState hook and shows when a user is typing. The handleSubmit function sends a message when the form is submitted, and handleUpload sends images. There is a text input field, a hidden image input field, and buttons for sending messages and uploading images to provide a complete message input interface.
In the MyMessage.jsx file, we will create a component to display the user's own messages.
// src\components\MyMessage.jsx
const MyMessage = ({ message }) => {
if (message.attachments && message.attachments.length > 0) {
return (
<img
src={message.attachments[0].file}
alt="message-attachment"
className="message-image"
style={{ float: 'right' }}
/>
);
}
return (
<div className="message" style={{ float: 'right', marginRight: '18px', backgroundColor: '#c3e4bd' }}>
{message.text}
</div>
);
};
export default MyMessage;
The MyMessage component handles how your own messages look in the chat. If your message has an image, it displays that image on the right. If it's just text, it shows the text in a styled box, also on the right. This helps make your messages easy to spot and nicely organized in the chat window.
In the TheirMessage.jsx file, we will create a component to display messages from other users.
// src\components\TheirMessage.jsx
const TheirMessage = ({ lastMessage, message }) => {
const isFirstMessageByUser = !lastMessage || lastMessage.sender.username !== message.sender.username;
return (
<div className="message-row">
{isFirstMessageByUser && (
<div
className="message-avatar"
style={{ backgroundImage: message.sender && `url(${message.sender.avatar})` }}
/>
)}
{message.attachments && message.attachments.length > 0
? (
<img
src={message.attachments[0].file}
alt="message-attachment"
className="message-image"
style={{ marginLeft: isFirstMessageByUser ? '4px' : '48px' }}
/>
)
: (
<div className="message" style={{ float: 'left', backgroundColor: '#fff', marginLeft: isFirstMessageByUser ? '4px' : '48px' }}>
{message.text}
</div>
)}
</div>
);
};
export default TheirMessage;
The TheirMessage component displays messages from other users in a chat. It shows the user's avatar next to the message if it's their first message in a sequence. If the message contains an image, it displays the image with a slight left margin. Text messages appear in a colored box aligned to the left, adjusting the margin based on whether it's the first message in that sequence from the user.
In the LoginForm.jsx file, we will create a login form for the chat application.
// src\components\LoginForm.jsx
import React, { useState } from 'react'
import axios from 'axios';
function LoginForm() {
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState('');
const handleSubmit = async (e) => {
e.preventDefault();
const authObject = { 'Project-ID': "Your_Project_Id", 'User-Name': username, "User-Secret": password }
try {
await axios.get('https://api.chatengine.io/chats', { headers: authObject });
localStorage.setItem('username', username);
localStorage.setItem('password', password);
window.location.reload();
} catch (error) {
setError('Invalid credentials. Please verify and try again.')
}
}
return (
<div className='wrapper'>
<div className='form'>
<h1 className='title'>Chat Application</h1>
<form onSubmit={handleSubmit}>
<input type="text" value={username} onChange={(e) => setUsername(e.target.value)} className='input' placeholder='Username' required />
<input type="password" value={password} onChange={(e) => setPassword(e.target.value)} className='input' placeholder='Password' required />
<div align="center">
<button type='submit' className='button'>
<span>START CHATTING</span>
</button>
</div>
<h2 className='error'>{error}</h2>
</form>
</div>
</div>
);
};
export default LoginForm;
Important: Make sure to replace "Your_Project_Id" with the actual Project ID you obtained earlier.
The LoginForm component uses useState hook to manage the state for username, password, and errors. When submitted (handleSubmit), it creates an authObject with username and password to authenticate via an API (axios.get) at https://api.chatengine.io/chats. On success, it saves the username and password in localStorage and reloads. If there's an error, it shows "Invalid credentials. Please verify and try again." The form includes username/password inputs, a submit button, and an error message display (h2.error).
In the LogoutButton.jsx file, we will create a logout button for the chat application.
// src\components\LogoutButton.jsx
const LogoutButton = () => {
const handleLogout = () => {
localStorage.removeItem('username');
localStorage.removeItem('password');
window.location.reload();
};
return (
<button onClick={handleLogout} className="logout-button">
Logout
</button>
);
};
export default LogoutButton;
The LogoutButton component in a React app lets users log out by clicking a "Logout" button. When clicked, it removes their stored username and password from the browser's memory (localStorage). Afterward, it refreshes the page to finish the logout process.
Integrating ChatEngine into Your Application
In the App.js file, we manage the chat application.
// src\App.js
import React from 'react'
import { ChatEngine } from 'react-chat-engine'
import ChatFeed from './components/ChatFeed'
import './App.css'
import LoginForm from './components/LoginForm'
import LogoutButton from './components/LogoutButton'
function App() {
if (!localStorage.getItem('username')) return <LoginForm />
return (
<>
<ChatEngine
height="100vh"
projectID="Your_Project_Id"
userName={localStorage.getItem('username')}
userSecret={localStorage.getItem('password')}
renderChatFeed={(chatAppProps) => <ChatFeed {...chatAppProps} />}
/>
<LogoutButton />
</>
)
}
export default App;
Important: Make sure to replace "Your_Project_Id" with the actual Project ID you obtained earlier.
This React App component manages a chat application. If there's no username stored, it displays a login form (LoginForm). If there's a stored username, it shows the chat interface (ChatEngine) with a custom feed (ChatFeed). Users can log out using the LogoutButton, which removes their stored credentials from the browser (local storage).
Styling Your Project
Add the following styles in your App.css file.
/* src\App.css */
/* General Styles */
* {
font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
margin: 0;
padding: 0;
box-sizing: border-box;
}
::-webkit-scrollbar {
width: 0;
background: transparent;
}
/* Chat List and Containers */
.ce-chat-list,
.ce-chats-container {
background-color: #222 !important;
}
.ce-chat-title-text {
color: #f2f2f2 !important;
}
.ce-active-chat-card {
background-color: #000 !important;
border: 2px solid #5d5d5d !important;
border-radius: 3px !important;
}
.ce-chat-form-container {
padding-bottom: 20px !important;
background-color: #222 !important;
color: white;
border-bottom: 1px solid #5d5d5d;
margin-bottom: 5px;
}
.ce-text-input {
border-radius: 50px !important;
margin-bottom: 10px;
border: 2px solid #bebebe !important;
background-color: #555;
color: white;
}
.ce-primary-button {
border-radius: 5px !important;
background-color: #000 !important;
border: 2px solid #dedede !important;
}
.ce-danger-button {
background-color: white !important;
border-radius: 5px !important;
}
.ce-settings {
background-color: #222 !important;
}
/* Autocomplete Input and Options */
.ce-autocomplete-input {
background-color: #555 !important;
color: white;
border-radius: 5px !important;
margin-top: 10px;
border: 2px solid #bebebe !important;
background-color: #555;
}
.ce-autocomplete-input::placeholder {
color: #bebebe;
}
.ce-autocomplete-options {
border-radius: 5px !important;
margin-top: 5px;
border: 1px solid #dedede !important;
background-color: white !important;
}
.ce-chat-settings-container {
padding-top: 12px !important;
}
.ce-person-text {
color: white;
}
.ce-chat-unread-dot {
background-color: #3ebd4e !important;
}
/* Person and Photo Titles */
.ce-person-title-container,
.ce-photo-title-container,
#ce-options-drop-down {
background-color: #555 !important;
color: white;
border-radius: 5px !important;
margin-top: 10px;
margin-bottom: 10px;
border: 2px solid #bebebe !important;
background-color: #555;
}
/* Delete Chat Button */
#ce-delete-chat-button,
.ce-danger-button {
background-color: crimson !important;
color: white !important;
}
#ce-delete-chat-button:hover {
background-color: rgb(201, 18, 55) !important;
}
/* Message Image */
.message-image {
border: 1px solid #ededed;
margin-top: 5px;
border-radius: 5px;
object-fit: cover;
max-height: 200px;
max-width: 200px;
min-height: 100px;
min-width: 100px;
}
/* Custom Feed */
.chat-feed {
height: 100%;
width: 100%;
overflow: scroll;
background-color: #000;
}
.chat-title-container {
padding: 18px;
text-align: center;
}
.chat-title {
color: #dedede;
font-weight: 800;
font-size: 24px;
}
.chat-subtitle {
color: #dedede;
font-weight: 600;
font-size: 12px;
padding-top: 4px;
}
.message-row {
float: left;
width: 100%;
display: flex;
margin-left: 18px;
}
.message-block {
width: 100%;
display: inline-block;
}
.message-avatar {
width: 40px;
height: 40px;
border-radius: 50%;
background-position: center;
background-size: 40px;
}
.message {
padding: 12px;
border-radius: 5px;
max-width: 60%;
}
/* Read Receipts */
.read-receipts {
position: relative;
bottom: 5px;
}
.read-receipt {
width: 15px;
height: 15px;
border-radius: 15px;
background-repeat: no-repeat;
background-position: center;
background-size: 15px;
}
/* Message Form */
.message-form-container {
position: absolute;
bottom: 0px;
width: 100%;
padding: 10px;
}
.message-form {
overflow: hidden;
border-radius: 5px;
border: 2px solid #ededed;
background-color: #000;
}
.message-input {
height: 40px;
width: calc(100% - 130px);
background-color: #000;
border: none;
color: white;
padding: 0px 18px;
outline: none;
font-size: 15px;
}
.image-button {
cursor: pointer;
padding: 0px 10px 10px 50px;
border: none;
height: 100%;
color: white;
}
.send-button {
height: 42px;
background-color: #000;
color: white;
border: none;
padding: 0px 18px;
cursor: pointer;
}
.send-icon,
.picture-icon {
top: 1px;
position: relative;
font-size: 15px;
}
/* Form Styles */
.wrapper {
height: 100vh;
width: 100%;
background: linear-gradient(#536976, #292E49);
display: grid;
place-items: center;
}
.input {
font-size: 18px;
margin: 0 auto;
padding: 20px 35px;
border-radius: 3px;
border: none;
width: 90%;
display: block;
transition: all 0.3s;
outline: none;
margin-bottom: 30px;
}
.form {
width: 450px;
}
.title {
text-align: center;
color: white;
margin-bottom: 30px;
font-size: 35px;
}
.button {
border-radius: 3px;
border: none;
font-size: 20px;
padding: 15px;
width: 200px;
transition: all 0.4s;
cursor: pointer;
margin: 5px;
width: 90%;
}
.button span {
cursor: pointer;
display: inline-block;
position: relative;
transition: 0.4s;
}
.button span:after {
content: '►';
position: absolute;
opacity: 0;
top: -5px;
right: -20px;
transition: 0.4s;
}
.button:hover span {
padding-right: 30px;
}
.button:hover span:after {
opacity: 1;
right: 0;
}
.error {
color: red;
text-align: center;
margin-top: 20px;
font-size: 18px;
}
/* Logout Button */
.logout-button {
padding: 10px 20px;
margin: 10px;
width: calc(100% - 76.5%);
background-color: crimson;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
position: absolute;
bottom: 0;
}
.logout-button:hover {
background-color: rgb(201, 18, 55) !important;
}
According to your project, you can further customize this project by adjusting the CSS. While our focus was primarily on functionality rather than responsive design in this implementation, you can tailor the CSS to suit your project's requirements and create a unique look.
Running Your Application
To run your application, execute the following command in the terminal:
npm start
Oh wow! Congratulations, we have completed this project together without any errors.
Important: Note that I have not mentioned any "Project-ID" in both App.js and LoginForm.jsx files, so kindly replace "Your_Project_Id" with your actual project ID.
Now surely some questions must be arising in your mind like we need another person for chatting so how to add a new user and how to create a group of more than one user? So let's see how we can do this.
Adding Users and Setting Up Group Chats
To add multiple users to your project, visit the ChatEngine site. Go to "My Project", then click on "Settings" and select "Users" from the left sidebar. Click on "New User" to create additional users for your project.
To add the created user to your project, open your project in the browser. In the top right corner, you'll see the "People" option. Click on it, then click on the input field. You'll see the username you created. Click on that name to add the person to the chat app. Now, both you and the new user can log in and chat in the application using any browser with your respective usernames and passwords.
Creating a group chat in ChatEngine.io involves a few simple steps. First, create users under the "Users" section. Once the users are set up, go to the "Chats" section and click on "New Chat". Enter a title for the chat, specify the admin username (one of the users you created earlier), and enter the access key (password).
Next, on the same page, you will find the "Members" option, click "Add member" and input the usernames of the users you want to include in the group chat. It's important to note that the users you add must already exist in the "Users" section. After adding all desired members, click "Save". Your group chat will be created and visible in your ChatEngine.io project, allowing all added users to participate in the chat.
And here's how your project will look in action: two users chatting seamlessly with each other.
Advanced Customization Options
Creating a real-time chat application using React JS not only allows you to build a basic chat interface but also gives you the power to customize it extensively. Here’s how you can take your chat application to the next level with advanced customization:
1. File and Media Sharing: To make your chat application more functional, allow users to share files, images, and videos. By integrating file upload capabilities, users can share media directly within the chat, making it a comprehensive communication tool.
2. Typing Indicators and Read Receipts: Improve the user experience by showing typing indicators and reading receipts. Typing indicators let users know when someone is composing a message, while read receipts show when a message has been read. This adds a layer of real-time interaction and transparency to your chat app.
3. Notifications and Alerts: Implement notifications and alerts to keep users informed about new messages even when they are not actively using the app. Push notifications and in-app alerts ensure that important messages are not missed.
4. Real-Time Analytics: Integrate real-time analytics to monitor the usage of your chat application. This can help you understand user behavior, track message volumes, and improve the overall performance of your app. Tools like Google Analytics or custom-built dashboards can provide these insights.
You can read the "Chat Engine" documentation to learn more about customization. Check the "Customize UI" section in the left sidebar for many options you can implement in your project
You have many functions and API calls to manage your chat application. You can delete or edit chats, retrieve data, and use event hooks to perform actions, such as playing music or showing animations. For example, the "onNewMessage" hook lets you play a sound when a new message arrives. Additionally, the server REST API allows you to get, edit, or delete users, and create new users for your chat.
Deploying Your Application
To deploy your application, you can use platforms like Netlify, Vercel, or GitHub Pages. I will demonstrate this project by deploying it on the Netlify site.
Project uploading using Netlify
Open your project in your VS code editor and execute this command: npm run build. This command will create a specific production-ready deployment for your react application, we're going to wait until the optimized production build is done. After building you can see in your project one folder will added named "build".
Next, go to the Netlify site and log in or sign in. Navigate to the left side "Sites" option you can see on the canter side the "browse to upload" option click on that and upload just the "build" folder. After one or two seconds your application will automatically deploy.
Next, click on the "Site Settings" option you will find the "Changes site name" option open it change your site name to whatever you want, and save it.
Open that site link that you created and you can see your site is deployed now anyone can use this link and open your site.
Conclusion
In just 20 minutes, we've developed and deployed a real-time chat application using React JS. We started by covering the prerequisites and setting up your ChatEngine.io account to get your project ID. Then, we added users and set up the initial project structure. Once we created the necessary files, we integrated ChatEngine into our app, adding styling to make it look great.
After that, we learned how to add users to the project as well as how to set up group chats. Also, we told you what are the customization options to improve the chat experience. As a final step, the application was deployed, so that everyone could access this project with a username and password and interact.
If you've read this article carefully, I hope you're confident and ready to create the chat application without any problems. If you still have questions about this article or web development in general, you can ask them in the question box given below, and you will get an answer soon.