Search code examples
javascriptreactjssass

How to fix the height in a chatbox to allow infinite scrolling? (react & scss)


I'm trying to create a chatbox, the messages all work fine but the styling is a bit off. After a certain amount of messages it only scrolls down to a certain amount but there's still more messages underneath.

Note: The chatbox container only takes up half the screen it has a height of 50vh

The Chat box

The newest message

The newest message is "LOL" it's under "sdfdsfdsfds" but the messages part of the chatbox won't allow me to scroll down anymore.

Here is the code snippet for the chatbox

 <div className="chat-box-container">
          <div className="chat-box-header">
            <h1>Global Chat</h1>

            <Button variant="danger" onClick={() => setOpenChat(false)}>
              X
            </Button>
          </div>

          <div className="chat-box-body">
            <div className="chat-box-messages">
              <div className="messages">
                {messages.map((message) => (
                  <Messages key={nanoid()} message={message} />
                ))}
              </div>
            </div>

            <div className="chat-box-players-online">
              <h1>Online</h1>
              <div className="players-online">
                <p>testtesttesttes</p>
                <p>test</p>
                <p>test</p>
                <p>test</p>
                <p>test</p>
                <p>test</p>
                <p>test</p>
                <p>test</p>
                <p>test</p>
                <p>test</p>
                <p>test</p>
                <p>test</p>

                <p>test</p>
                <p>test</p>
                <p>test</p>
                <p>test</p>

                <p>test1</p>
                <p>test2</p>
                <p>test3</p>
                <p>test4</p>

                <p>test1</p>
                <p>test2</p>
                <p>test3</p>
                <p>test4</p>

                <p>test1</p>
                <p>test2</p>
                <p>test3</p>
                <p>test5</p>
              </div>
            </div>

            <div className="chat-box-message">
              <Message user={user} token={token} socket={socket} />
            </div>
          </div>
        </div>
.chat-box-container {
  width: 100vw;
  height: 50vh;
  position: fixed;
  bottom: 0%;
  right: 0%;
  border-radius: 1em;
  background-color: #282e33;
  box-shadow: 5px 5px 15px 5px #000000;

  .chat-box-header {
    color: white;
    display: grid;
    grid-template-columns: 1fr 50px;
    justify-content: center;
    border-bottom: 1px solid gray;

    h1 {
      display: flex;
      align-items: center;
      justify-content: center;
    }
  }

  .chat-box-body {
    color: white;
    margin: 0 auto;
    display: grid;
    grid-template-columns: 1fr 150px;

    .chat-box-messages {
      height: 100vh;

      .messages {
        padding-left: 3%;
        border-radius: 1em;
        height: 40%;
        overflow-y: auto;
      }
    }

    .chat-box-players-online {
      border-left: 1px solid gray;
      border-radius: 1em;
      height: 100vh;

      h1 {
        border-bottom: 1px solid gray;
        text-align: center;
      }

      .players-online {
        padding-left: 5%;
        height: 35%;
        overflow-y: auto;
      }
    }

    .chat-box-message {
      grid-column: 1 / -1;
      width: 100%;
      border-radius: 1em;
      position: fixed;
      bottom: 0%;
    }
  }
}

The one with a className of "chat-box-messages" is all the messages, and the one with "chat-box-message" is just the input box.

The player's online part of it does not have this issue, no matter the height or width the player's online always allows infinite scrolling and always shows all the players.


Solution

  • You can use Javascript to auto scroll regardless of the contents and even disable it if the user scrolled up manually:

    const chatElement = document.getElementById('your_chat_element_id');
    const scrollDiff = (chatElement.scrollHeight - chatElement.scrollTop) - chatElement.clientHeight;
    
    if(scrollDiff < 450){
        chatElement.scrollTop = chatElement.scrollHeight;
    }
    

    Just make sure that snippet runs every time a message is received or however you're polling the contents from the server.

    Here's a functional example:

    var toggleChat;
    
    document.addEventListener("DOMContentLoaded", function(e){
        let chatRunning = false;
      
      toggleChat = function(){
        chatRunning = !chatRunning;
        let nrMsg = 0;
        
        let chatTimer;
        
        if(chatRunning){
                chatTimer = setInterval(function(){
            if(!chatRunning){
                clearInterval(chatTimer);
            }
            nrMsg++;
            document.getElementById('chatWindow').innerHTML += "<p>This is message: "+ nrMsg +"</p>";
            
            // auto scroll
                    const chatElement = document.getElementById('chatWindow');
            const scrollDiff = (chatElement.scrollHeight - chatElement.scrollTop) - chatElement.clientHeight;
    
            if(scrollDiff < 450){
                chatElement.scrollTop = chatElement.scrollHeight;
            }
          }, 500);
        }
        
      }
    });
    #chatWindow {
      width: 300px;
      height: 300px;
      border: 2px solid black;
      overflow: auto;
    }
    <div id="chatWindow">
    
    </div>
    
    <button onclick="toggleChat()">
    Toggle Chat
    </button>