Unlock the Power of Chatbots with React. Chatbots have become an integral part of our digital lives, from assisting with shopping to providing instant answers. Building a chatbot may seem daunting, but with React.js and CSS, you can create a sophisticated and functional AI chatbot in just a few steps.
Through this process, you’ll gain hands-on experience with essential concepts such as:
- Building reusable components
- Managing state and user interactions
- Integrating APIs for seamless functionality
By the end, you’ll have a sleek, functional chatbot to enhance your projects and a deeper understanding of React.js and CSS.”
In this step-by-step guide, we’ll create a dynamic AI-powered chatbot using React JS and CSS, leveraging the free Google Gemini API for intelligent responses. You’ll learn how to tailor the chatbot to work seamlessly with your own data, making it a valuable asset for your portfolio.
By completing this project, you’ll gain a practical, real-world example of AI-driven development, perfect for showcasing your skills in today’s AI-centric landscape. Plus, you can easily integrate this chatbot into your website, application, or client projects.
Looking for a JavaScript challenge? Check out our companion blog post to build the same AI chatbot using vanilla JavaScript, complete with advanced features like file uploads and emoji pickers. This is an excellent opportunity to hone your JavaScript skills and develop a practical, functional project.”
Why Build an AI Chatbot in React JS?
Building an AI-powered chatbot with React.js and CSS is a rewarding project that goes beyond just having fun. It’s an opportunity to develop in-demand skills and gain hands-on experience with:
- React Fundamentals: Master components, state management, and hooks.
- AI Integration: Harness the power of the Gemini API for dynamic, AI-driven responses.
- Web Services: Learn to interact with APIs, handle asynchronous operations, and manage data fetching.
By completing this project, you’ll have a portfolio-worthy chatbot that showcases your skills and can be used in real-world applications. Enhance your resume, impress potential employers, and take your development skills to the next level.”
Setting Up the Project
Create a Project Folder:
- Make a new folder, for instance, “chatbot-reactjs”. (Or any name you feel good with)
- Open this folder in your VS Code editor. (Or any code editor)
Initialize the Project:
Open your terminal by pressing Ctrl + J and then use Vite to create a new React app with this command:
npm create vite@latest ./ -- --template react
Install necessary dependencies and start the development server:
npm install
npm run dev
If your project is running in your browser, congratulations! You’ve successfully set up your chat app. Now, let’s move on to modifying folders and files.
Modify folder and CSS Files:
- Remove the default
assets
folder andApp.css
file. - Replace the content of
index.css
with the provided CSS code.
/* Importing Google Fonts - Inter */
@import url('https://fonts.googleapis.com/css2?family=Inter:opsz,[email protected],100..900&display=swap');
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: "Inter", sans-serif;
}
body {
width: 100%;
min-height: 100vh;
background: linear-gradient(#F4F0FF, #DACDFF);
}
#chatbot-toggler {
position: fixed;
bottom: 30px;
right: 35px;
border: none;
height: 50px;
width: 50px;
display: flex;
cursor: pointer;
align-items: center;
justify-content: center;
border-radius: 50%;
background: #6D4FC2;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.1);
transition: all 0.2s ease;
}
.container.show-chatbot #chatbot-toggler {
transform: rotate(90deg);
}
#chatbot-toggler span {
color: #fff;
position: absolute;
}
#chatbot-toggler span:last-child,
.container.show-chatbot #chatbot-toggler span:first-child {
opacity: 0;
}
.container.show-chatbot #chatbot-toggler span:last-child {
opacity: 1;
}
.chatbot-popup {
position: fixed;
width: 420px;
opacity: 0;
right: 35px;
bottom: 90px;
pointer-events: none;
transform: scale(0.2);
overflow: hidden;
background: #fff;
border-radius: 15px;
transform-origin: bottom right;
box-shadow: 0 0 128px 0 rgba(0, 0, 0, 0.1),
0 32px 64px -48px rgba(0, 0, 0, 0.5);
transition: all 0.1s ease;
}
.container.show-chatbot .chatbot-popup {
opacity: 1;
pointer-events: auto;
transform: scale(1);
}
.chatbot-popup .chat-header {
display: flex;
padding: 15px 22px;
align-items: center;
background: #6D4FC2;
justify-content: space-between;
}
.chat-header .header-info {
display: flex;
gap: 10px;
align-items: center;
}
.header-info svg {
width: 35px;
height: 35px;
flex-shrink: 0;
padding: 6px;
fill: #6D4FC2;
background: #fff;
border-radius: 50%;
}
.header-info .logo-text {
color: #fff;
font-weight: 600;
font-size: 1.31rem;
letter-spacing: 0.02rem;
}
.chat-header button {
border: none;
height: 40px;
width: 40px;
color: #fff;
cursor: pointer;
padding-top: 2px;
margin-right: -10px;
font-size: 1.9rem;
border-radius: 50%;
background: none;
transition: 0.2s ease;
}
.chat-header button:hover {
background: #593bab;
}
.chat-body {
display: flex;
flex-direction: column;
gap: 20px;
height: 460px;
overflow-y: auto;
margin-bottom: 82px;
padding: 25px 22px;
scrollbar-width: thin;
scrollbar-color: #DDD3F9 transparent;
}
.chat-body .message {
display: flex;
gap: 11px;
align-items: center;
}
.chat-body .message svg {
width: 35px;
height: 35px;
flex-shrink: 0;
padding: 6px;
fill: #fff;
align-self: flex-end;
margin-bottom: 2px;
background: #6D4FC2;
border-radius: 50%;
}
.chat-body .message .message-text {
padding: 12px 16px;
max-width: 75%;
font-size: 0.95rem;
word-wrap: break-word;
white-space: pre-line;
}
.chat-body .message.error .message-text {
color: #ff0000;
}
.chat-body .bot-message .message-text {
background: #F6F2FF;
border-radius: 13px 13px 13px 3px;
}
.chat-body .user-message {
flex-direction: column;
align-items: flex-end;
}
.chat-body .user-message .message-text {
color: #fff;
background: #6D4FC2;
border-radius: 13px 13px 3px 13px;
}
.chat-footer {
position: absolute;
bottom: 0;
width: 100%;
background: #fff;
padding: 15px 22px 20px;
}
.chat-footer .chat-form {
display: flex;
align-items: center;
position: relative;
background: #fff;
border-radius: 32px;
outline: 1px solid #CCCCE5;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.06);
}
.chat-form:focus-within {
outline: 2px solid #6D4FC2;
}
.chat-form .message-input {
width: 100%;
height: 47px;
border: none;
outline: none;
font-size: 0.95rem;
padding: 0 17px;
background: none;
}
.chat-form #send-message {
height: 35px;
width: 35px;
border: none;
flex-shrink: 0;
color: #fff;
cursor: pointer;
display: none;
margin-right: 6px;
background: #6D4FC2;
border-radius: 50%;
font-size: 1.15rem;
transition: 0.2s ease;
}
.chat-form .message-input:valid~#send-message {
display: block;
}
.chat-form #send-message:hover {
background: #593bab;
}
/* Responsive media query for mobile screens */
@media (max-width: 520px) {
#chatbot-toggler {
right: 20px;
bottom: 20px;
}
.chatbot-popup {
right: 0;
bottom: 0;
height: 100%;
border-radius: 0;
width: 100%;
}
.chatbot-popup .chat-header {
padding: 12px 15px;
}
.chat-body {
height: calc(90% - 55px);
padding: 25px 15px;
}
.chat-footer {
padding: 10px 15px 15px;
}
}
Step 1: Set Up Your Component Files
In the src
directory of your project, create a new folder named components
. Inside this folder, create the following three files:
ChatbotIcon.jsx
ChatForm.jsx
ChatMessage.jsx
These files will serve as the building blocks for your chatbot’s user interface.
Step 2: Define Component Layout and Functionality
Add the respective code to each of the newly created files:
- In
components/ChatbotIcon.jsx
, add the code to render the chatbot’s SVG icon. - In
components/ChatForm.jsx
, add the code to define the chat form’s layout and functionality. - In
components/ChatMessage.jsx
, add the code to define the chat message’s layout and functionality.
By adding the necessary code to each file, you’ll begin to bring your chatbot to life.
const ChatbotIcon = () => {
return (
<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50" viewBox="0 0 1024 1024">
<path d="M738.3 287.6H285.7c-59 0-106.8 47.8-106.8 106.8v303.1c0 59 47.8 106.8 106.8 106.8h81.5v111.1c0 .7.8 1.1 1.4.7l166.9-110.6 41.8-.8h117.4l43.6-.4c59 0 106.8-47.8 106.8-106.8V394.5c0-59-47.8-106.9-106.8-106.9zM351.7 448.2c0-29.5 23.9-53.5 53.5-53.5s53.5 23.9 53.5 53.5-23.9 53.5-53.5 53.5-53.5-23.9-53.5-53.5zm157.9 267.1c-67.8 0-123.8-47.5-132.3-109h264.6c-8.6 61.5-64.5 109-132.3 109zm110-213.7c-29.5 0-53.5-23.9-53.5-53.5s23.9-53.5 53.5-53.5 53.5 23.9 53.5 53.5-23.9 53.5-53.5 53.5zM867.2 644.5V453.1h26.5c19.4 0 35.1 15.7 35.1 35.1v121.1c0 19.4-15.7 35.1-35.1 35.1h-26.5zM95.2 609.4V488.2c0-19.4 15.7-35.1 35.1-35.1h26.5v191.3h-26.5c-19.4 0-35.1-15.7-35.1-35.1zM561.5 149.6c0 23.4-15.6 43.3-36.9 49.7v44.9h-30v-44.9c-21.4-6.5-36.9-26.3-36.9-49.7 0-28.6 23.3-51.9 51.9-51.9s51.9 23.3 51.9 51.9z" />
</svg>
);
};
export default ChatbotIcon;
In components/ChatForm.jsx, add the code to create the chat form. It will handle form submission, update the component’s state with user input, and call the generateBotResponse function to fetch responses from the API.
import { useRef } from "react";
const ChatForm = ({ chatHistory, setChatHistory, generateBotResponse }) => {
const inputRef = useRef();
const handleFormSubmit = (e) => {
e.preventDefault();
const userMessage = inputRef.current.value.trim();
if (!userMessage) return;
inputRef.current.value = "";
// Update chat history with the user's message
setChatHistory((history) => [...history, { role: "user", text: userMessage }]);
// Delay 600 ms before showing "Thinking..." and generating response
setTimeout(() => {
// Add a "Thinking..." placeholder for the bot's response
setChatHistory((history) => [...history, { role: "model", text: "Thinking..." }]);
// Call the function to generate the bot's response
generateBotResponse([...chatHistory, { role: "user", text: `Using the details provided above, please address this query: ${userMessage}` }]);
}, 600);
};
return (
<form onSubmit={handleFormSubmit} className="chat-form">
<input ref={inputRef} placeholder="Message..." className="message-input" required />
<button type="submit" id="send-message" className="material-symbols-rounded">
arrow_upward
</button>
</form>
);
};
export default ChatForm;
In components/ChatMessage.jsx, add the code to display chat messages. Differentiate between user messages and bot replies with the unique class name for stylings.
import ChatbotIcon from "./ChatbotIcon";
const ChatMessage = ({ chat }) => {
return (
!chat.hideInChat && (
<div className={`message ${chat.role === "model" ? "bot" : "user"}-message ${chat.isError ? "error" : ""}`}>
{chat.role === "model" && <ChatbotIcon />}
<p className="message-text">{chat.text}</p>
</div>
)
);
};
export default ChatMessage;
Next, create a companyInfo.js file inside the src, outside of the components folder.
// Dummy company information for chabot
export const companyInfo = `
Introduction:
I'm your friendly Aroma Beans Coffee chatbot, here to assist you with anything you need related to our coffee shop! Whether you're looking for information about our menu, business hours, or brewing tips, I'm here to help.
Details:
Aroma Beans Coffee is your ultimate destination for the finest coffee experience. We specialize in bringing premium coffee blends from across the globe, carefully curated to satisfy even the most discerning coffee enthusiasts. Whether you're a fan of single-origin beans or enjoy exploring bold, unique blends, Aroma Beans Coffee promises to elevate your coffee moments.
Located in the heart of Brew City, California, our café and roastery provide a cozy, welcoming atmosphere for coffee lovers to relax, work, or connect. Visit us at 123 Coffee Lane, Brew City, CA 90210. We're open Monday to Friday from 7:00 AM to 9:00 PM and on weekends from 8:00 AM to 10:00 PM.
Stay connected with us through our vibrant social media community. Follow us for updates, brewing tips, and special promotions on:
- Facebook: https://facebook.com/aromabeanscoffee
- Instagram: https://instagram.com/aromabeanscoffee
- Twitter: https://twitter.com/aromabeansco
- LinkedIn: https://linkedin.com/company/aromabeanscoffee
For inquiries, feel free to reach out via email at [email protected] or call us at +1 (555) 123-4567.
Our website, https://www.aromabeanscoffee.com, offers a seamless shopping experience for coffee beans, accessories, and subscriptions. Learn about our unique blends, explore brewing guides, and subscribe to receive fresh coffee delivered to your doorstep.
Menu:
- Signature Coffee:
- Espresso Shot - $3.50
- Cappuccino - $4.00
- Latte (Classic/Vanilla/Caramel) - $4.50
- Mocha - $5.00
- Specialty Brews:
- Cold Brew - $4.50
- Nitro Cold Brew - $5.50
- Single-Origin Pour Over - $5.00
- Seasonal Favorites:
- Pumpkin Spice Latte - $5.50
- Peppermint Mocha - $5.50
- Tea & Alternatives:
- Matcha Latte - $5.00
- Chai Latte - $4.50
- Hot Chocolate - $4.00
- Snacks & Pastries:
- Croissant (Butter/Almond) - $3.50
- Muffins (Blueberry/Chocolate Chip) - $3.00
- Avocado Toast - $6.00
- Bagel with Cream Cheese - $4.00
At Aroma Beans Coffee, we believe in creating moments worth savoring. Whether you're stopping by for your morning pick-me-up or indulging in an afternoon treat, we've got something special for everyone.
`;
Finally, update the content of src/App.jsx with the provided code.
import { useEffect, useRef, useState } from "react";
import ChatbotIcon from "./components/ChatbotIcon";
import ChatForm from "./components/ChatForm";
import ChatMessage from "./components/ChatMessage";
import { companyInfo } from "./companyInfo";
const App = () => {
const chatBodyRef = useRef();
const [showChatbot, setShowChatbot] = useState(false);
const [chatHistory, setChatHistory] = useState([
{
hideInChat: true,
role: "model",
text: companyInfo,
},
]);
const generateBotResponse = async (history) => {
// Helper function to update chat history
const updateHistory = (text, isError = false) => {
setChatHistory((prev) => [...prev.filter((msg) => msg.text != "Thinking..."), { role: "model", text, isError }]);
};
// Format chat history for API request
history = history.map(({ role, text }) => ({ role, parts: [{ text }] }));
const requestOptions = {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ contents: history }),
};
try {
// Make the API call to get the bot's response
const response = await fetch(import.meta.env.VITE_API_URL, requestOptions);
const data = await response.json();
if (!response.ok) throw new Error(data?.error.message || "Something went wrong!");
// Clean and update chat history with bot's response
const apiResponseText = data.candidates[0].content.parts[0].text.replace(/\*\*(.*?)\*\*/g, "$1").trim();
updateHistory(apiResponseText);
} catch (error) {
// Update chat history with the error message
updateHistory(error.message, true);
}
};
useEffect(() => {
// Auto-scroll whenever chat history updates
chatBodyRef.current.scrollTo({ top: chatBodyRef.current.scrollHeight, behavior: "smooth" });
}, [chatHistory]);
return (
<div className={`container ${showChatbot ? "show-chatbot" : ""}`}>
<button onClick={() => setShowChatbot((prev) => !prev)} id="chatbot-toggler">
<span className="material-symbols-rounded">mode_comment</span>
<span className="material-symbols-rounded">close</span>
</button>
<div className="chatbot-popup">
{/* Chatbot Header */}
<div className="chat-header">
<div className="header-info">
<ChatbotIcon />
<h2 className="logo-text">Chatbot</h2>
</div>
<button onClick={() => setShowChatbot((prev) => !prev)} className="material-symbols-rounded">
keyboard_arrow_down
</button>
</div>
{/* Chatbot Body */}
<div ref={chatBodyRef} className="chat-body">
<div className="message bot-message">
<ChatbotIcon />
<p className="message-text">
Hey there <br /> How can I help you today?
</p>
</div>
{/* Render the chat history dynamically */}
{chatHistory.map((chat, index) => (
<ChatMessage key={index} chat={chat} />
))}
</div>
{/* Chatbot Footer */}
<div className="chat-footer">
<ChatForm chatHistory={chatHistory} setChatHistory={setChatHistory} generateBotResponse={generateBotResponse} />
</div>
</div>
</div>
);
};
export default App;
Important: Your chatbot won’t generate responses until it’s connected to the Gemini API. Sign up for a free API key from Google AI Studio. Once you have your key, create a .env file.
VITE_API_URL=https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key=YOUR-API-KEY-HERE