Auto scroll to the bottom in a react chat application
Today we’ll show you how to auto scroll to the bottom in a react chat application. In this article, we will create a react app to simulate the chat application and automatically set the scroll position on the new message.
There are many packages available to achieve this functionality but we will use the DOMNodeInserted
JavaScript event to manage the scroll position in ReactJS.
Steps to implement chatbot auto scroll to the bottom
- Create a react application
- Create a chatbot design
- Write a function to generate dummy messages
- Manage auto scroll to the bottom
- Output
1. Create a react application
First, we will create a react application using the create-react-app
package. Run the following command to create a react app.
1 | npx create-react-app scroll-to-bottom-react-chat-app |
2. Create a chatbot design
Now, let’s create a simple chatbot design to simulate the functionality. We’ll consider the three parts such as header, messages and footer (input area) in the chatbot. Use the following code for the design.
App.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | import React, { useState } from 'react'; import sendIcon from './send.svg'; function App() { const [messages, setMessages] = useState([]); return ( <div className="App"> <h3>Auto scroll to bottom in react chat app - <a href="https://www.cluemediator.com" target="_blank" rel="noopener noreferrer">Clue Mediator</a></h3> <div className="chat"> <div className="head">ChatBot</div> <div className="messages"> {messages.map((m, i) => <div key={i} className={`msg${i % 2 !== 0 ? ' dark' : ''}`}>{m}</div>)} </div> <div className="footer"> <input type="text" placeholder="Type here..." /> <img src={sendIcon} /> </div> </div> </div> ); } export default App; |
index.css
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | body { margin: 20px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } code { font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace; } .chat { border: 1px solid #ddd; width: 350px; height: 450px; border-radius: 4px; overflow: hidden; margin-left: 50px; } .head { background: #2d3436; padding: 10px; border-bottom: 1px solid #ccc; font-weight: 600; color: #f5f5f5; } .messages { height: 342px; overflow-y: auto; padding: 15px 10px; } .msg { border: 1px solid #ddd; padding: 7px 15px; border-radius: 20px; font-size: 13px; background: #dfe6e9; margin-bottom: 20px; width: 80%; float: left; } .msg.dark { float: right; background: #00cec9; } .footer { display: flex; border-top: 1px solid #ddd; } input { padding: 10px; width: 290px; border: 0; margin-right: 10px; } input:focus { outline: none; } .footer img { cursor: pointer; } |
3. Write a function to generate dummy messages
We have to write a function to generate dummy messages so we can simulate the chatbot responses. Check out the following code to generate messages.
1 2 3 4 5 6 7 | const generateMessage = () => { const words = ["The sky", "above", "the port", "was", "the color of television", "tuned", "to", "a dead channel", ".", "All", "this happened", "more or less", ".", "I", "had", "the story", "bit by bit", "from various people", "and", "as generally", "happens", "in such cases", "each time", "it", "was", "a different story", ".", "It", "was", "a pleasure", "to", "burn"]; const text = []; let x = 7; while (--x) text.push(words[Math.floor(Math.random() * words.length)]); return text.join(" "); } |
4. Manage auto scroll to the bottom
To manage auto scroll to the bottom of the message list div, we will use the DOMNodeInserted
javascript event along with the refs
in React Hooks. Also, use the above function to send a dummy message every two seconds.
App.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | import React, { useEffect, useRef, useState } from 'react'; import sendIcon from './send.svg'; const generateMessage = () => { const words = ["The sky", "above", "the port", "was", "the color of television", "tuned", "to", "a dead channel", ".", "All", "this happened", "more or less", ".", "I", "had", "the story", "bit by bit", "from various people", "and", "as generally", "happens", "in such cases", "each time", "it", "was", "a different story", ".", "It", "was", "a pleasure", "to", "burn"]; const text = []; let x = 7; while (--x) text.push(words[Math.floor(Math.random() * words.length)]); return text.join(" "); } function App() { const messageEl = useRef(null); const [messages, setMessages] = useState([]); useEffect(() => { if (messageEl) { messageEl.current.addEventListener('DOMNodeInserted', event => { const { currentTarget: target } = event; target.scroll({ top: target.scrollHeight, behavior: 'smooth' }); }); } }, []) useEffect(() => { const generateDummyMessage = () => { setInterval(() => { setMessages(prevMsg => [...prevMsg, generateMessage()]); }, 2000); } generateDummyMessage(); }, []); return ( <div className="App"> <h3>Auto scroll to bottom in react chat app - <a href="https://www.cluemediator.com" target="_blank" rel="noopener noreferrer">Clue Mediator</a></h3> <div className="chat"> <div className="head">ChatBot</div> <div className="messages" ref={messageEl}> {messages.map((m, i) => <div key={i} className={`msg${i % 2 !== 0 ? ' dark' : ''}`}>{m}</div>)} </div> <div className="footer"> <input type="text" placeholder="Type here..." /> <img src={sendIcon} /> </div> </div> </div> ); } export default App; |
5. Output
Run the application and check the output in the browser.
That’s it for today.
Thank you for reading. Happy Coding..!!
Thanks for this great article. Very simple and straightforward solution to an otherwise annoying problem.
Glad it helped!
Thanks mate !
I with you completely agree.
In it something is. Thanks for an explanation, I too consider, that the easier the better …
You are absolutely right. In it something is also to me this idea is pleasant, I completely with you agree.