Chatbots are everywhere, helping with shopping, answering questions, and more. Building one might sound tricky, but with React.js and CSS, it’s surprisingly simple. In just a few steps, you can create a sleek, functional AI chatbot for your projects while learning key concepts like components, state management, and API integration.
In this post, I’ll guide you through creating an AI-powered chatbot using React JS and CSS. We’ll use the free Google Gemini API for dynamic responses, and learn how to customize the chatbot to work with your own data. By the end, you’ll have a practical project to showcase in your portfolio, making it an excellent addition to today’s AI-driven world.
Want to build the same AI chatbot in JavaScript with cool features like file uploads and emoji pickers? Check out this blog post! It’s a great way to sharpen your vanilla JavaScript skills and try something practical.
Why Build an AI Chatbot in React JS?
Creating an AI-powered chatbot with React.js and CSS is more than just a fun project. It’s a great way to build valuable skills and here’s what you’ll learn:
- React Basics: Practice working with components, state management, and hooks.
- AI API Integration: Use the Gemini API to fetch dynamic, AI-powered responses.
- Web Services: Understand how to interact with APIs, handle asynchronous operations, and manage data fetching.
- Portfolio-Worthy Project: Build a practical chatbot you can showcase or use for real-world use.
Video Tutorial to AI Chatbot in React JS
The YouTube tutorial above is an excellent resource if you prefer video learning. It covers every line of code in detail, with helpful comments to make the process easy to follow. For those who prefer a written guide, keep reading as we break down each step of the chatbot project.
Setting Up the Project
Before you start building the AI chatbot with React.js and CSS, make sure Node.js is installed on your computer. If not, download and install it from the official Node.js website.
Create a Project Folder:
- Make a new folder, for instance, “chatbot-reactjs”.
- Open this folder in your VS 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 weather 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; } }
Creating the Components
Within the src
directory of your project, organize your files by creating a “components” folder. Inside the components folder, create the following files:
- ChatbotIcon.jsx
- ChatForm.jsx
- ChatMessage.jsx
Adding the Codes
Add the respective code to each newly created file to define the layout and functionality of your chatbot.
In components/ChatbotIcon.jsx
, add the code to display the chatbot’s SVG icon.
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. Use this file to add custom data, like details about your company. For example, you can include dummy content about a coffee shop as a placeholder, or replace it with your own data.
// 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. This file imports everything together, using your components to build the chatbot. It handles API requests, controls the chatbot’s visibility, and makes sure everything works smoothly.
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 in the root directory of your project and add the following code with your API key.
VITE_API_URL=https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key=YOUR-API-KEY-HERE
Your key should look something like this: AIzaSyAtpnKGX14bTgmx0l_gQeatYvdWvY_wOTQ.
Congrats! If you’ve followed all the steps correctly, your AI chatbot should now be live in your browser. Test it by asking questions, toggling the popup, and exploring how it works.
Conclusion and final words
Building an AI chatbot with React.js and CSS is a great way to level up your skills and create something valuable. It not only deepens your knowledge of React and API integration but also gives you a practical project you can proudly showcase.
Keep experimenting! You can add features like an emoji picker, file upload, or a color theme switcher. Try improving error handling and adding other cool updates to make your chatbot even better.
If you encounter any issues, feel free to download the source code files for this AI chatbot project for free by clicking the “Download” button. Be sure to read the README.md
file included in the zip for detailed instructions on how to set up and run the project.