Clue Mediator

Auto scroll to the bottom in a react chat application

📅September 30, 2020

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

  1. Create a react application
  2. Create a chatbot design
  3. Write a function to generate dummy messages
  4. Manage auto scroll to the bottom
  5. 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.

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

import React, { useState } from 'react';
import sendIcon from './send.svg';

function App() {

  const [messages, setMessages] = useState([]);

  return (
    <div class="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 class="chat">
        <div class="head">ChatBot</div>
        <div class="messages">
          {messages.map((m, i) => <div 0="" 2="" key={i} class="{`msg${i" %="" !="=" ?="" '="" dark'="" :="" ''}`}="">{m}</div>)}
        </div>
        <div class="footer">
          <input type="text" placeholder="Type here...">
          <img src={sendIcon}>
        </div>
      </div>
    </div>
  );
}

export default App;

index.css

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.

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

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 class="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 class="chat">
        <div class="head">ChatBot</div>
        <div class="messages" ref={messageEl}>
          {messages.map((m, i) => <div 0="" 2="" key={i} class="{`msg${i" %="" !="=" ?="" '="" dark'="" :="" ''}`}="">{m}</div>)}
        </div>
        <div class="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.

Output - Auto scroll to the bottom in a react chat application - Clue Mediator

Output - Auto scroll to the bottom in a react chat application - Clue Mediator

That’s it for today.
Thank you for reading. Happy Coding..!!

Demo & Source Code

Github Repository StackBlitz Project