How can I use an auto scroll to the bottom of the page?

Hi, I 've seen default scroll responses to specific areas of the code, but I still having a doubt. I’m building an app that sends messages to the screen and I want to know if there is any way to make the page does scroll to the bottom when the size of the messages are bigger than the size of the screen by default.

Thanks you so much.

1 Like

I also want to know this. I have tried almost all methods that cannot achieve automatic scrolling to the bottom. The only way to scroll to the bottom is to set an anchor point at the bottom, and then click the link to jump to scroll the page to the bottom, but this is not automatic

Here is a related response about scrolling to the bottom of a text area:

If you want to scroll to the bottom the page, here’s a modification of my previous answer:

import streamlit as st

if 'chat' not in st.session_state:
    st.session_state.chat = "A: Hello"

def submit():
    st.session_state.chat += f'  \nB: {st.session_state.B}'
    st.session_state.chat += '  \nA: Some response.'
    # Clear the text input widget for convenience
    st.session_state.B = ''

st.write(st.session_state.chat)

st.text_input('B\'s Response', key='B', on_change=submit)

# Define the scroll operation as a function and pass in something unique for each
# page load that it needs to re-evaluate where "bottom" is
js = f"""
<script>
    function scroll(dummy_var_to_force_repeat_execution){{
        var textAreas = parent.document.querySelectorAll('section.main');
        for (let index = 0; index < textAreas.length; index++) {{
            textAreas[index].style.color = 'red'
            textAreas[index].scrollTop = textAreas[index].scrollHeight;
        }}
    }}
    scroll({len(st.session_state.chat)})
</script>
"""

st.components.v1.html(js)
2 Likes

“I was unable to achieve the effect of automatic scrolling in the py file, but I observed the front-end code and found that the height of the page’s’ body 'was always 0. In fact, the container you are currently using needs scrolling.”. I tried using st. components. v1. html () to execute JavaScript code, but this is not feasible. Because this method embeds an html under the iframe tag, the JavaScript code will be executed in this html without affecting the home page. Finally, I can only add the effect of automatic scrolling by modifying the local default ‘index. html’ front-end page, which requires modifying the files in the streamlit package. If you don’t mind later version iterations, you can use this method. Generally, the default ‘index. html’ file is located in your local folder, streamlint /static, where you can make the following modifications:

<script>

document.addEventListener('DOMContentLoaded', function() {
  // Write the code that needs to be executed after the document is loaded here
  // Here, priority is given to locating the completed div tags that can be loaded by opening the page
  const targetDiv = document.querySelector('#root > div:nth-child(1) > div.withScreencast > div > div');
  const observer = new MutationObserver(function(mutations) {
  // Execute the corresponding code when detecting a change in the div element
  // Locate the div tag that requires automatic scrolling here
  const parentDiv = document.querySelector("#root > div:nth-child(1) > div.withScreencast > div > div > div > section.main.css-k1vhr4.egzxvld5");
  // Locate your content div tag here. We need to scroll through the height of this content
  const targetDiv = document.querySelector(".block-container.css-k1ih3n.egzxvld4 > div:nth-child(1) > div");
  const height = targetDiv.getBoundingClientRect().height;
  // Enable scrolling
  parentDiv.scrollTop = height;
    });

    // Options for configuring a MutationObserver instance
    const config = { attributes: true, childList: true, subtree: true };

    // Start the MutationObserver instance
    if (targetDiv) {
    observer.observe(targetDiv, config);
    };
});

</script>

Note: Thistag needs to be placed below thetag to ensure that the component is loaded before testing

2 Likes

I’m trying to achieve the same for a markdown (chat) container, specifically I’m developing a chatbot application that uses OpenAI’s GPT-4 model for conversation. In this application, the chat history is displayed in a predefined div with class “chat-container”. New messages are appended to this div, and the most recent message should be displayed automatically by scrolling to the bottom of the div.

I’ve tried several JavaScript-based solutions to auto-scroll the div to the bottom, but so far none of them have worked. Here’s a sample of the JavaScript that I tried implementing:

<script>
    // Select the node that will be observed for mutations
    const chatContainer = document.querySelector('.chat-container');

    // Create a new instance of 'MutationObserver' named 'observer', 
    // passing it a callback function
    const observer = new MutationObserver(function() {
        chatContainer.scrollTop = chatContainer.scrollHeight;
    });

    // Start observing the target node for configured mutations
    observer.observe(chatContainer, { childList: true });
</script>

The main issue is that this script doesn’t seem to trigger when a new message is added, and the scroll position remains at the current message instead of moving to the most recent message.

I’m interested in hearing if anyone has experienced a similar issue and if there are any known solutions or workarounds. Specifically, is there a way to auto-scroll to the most recent message in the chat history in Streamlit?

Javascript will not keep re-executing automatically. You have to either remove it and rewrite, or throw in a dummy variable like an integer that you increment thereby changing the script with each page load so it reruns.

Thanks a lot for the swift reply and the suggestion regarding the re-execution of Javascript in Streamlit. I implemented the recommended approach of using a dummy variable to force a change and hence a re-run of the script. The dummy variable increments properly, so there is a change on each page load. However, the desired effect - auto-scrolling to the bottom of a chat - isn’t happening.

Here is the JavaScript code snippet I’m using:

st.markdown(
    """
    <script>
    var element = document.getElementById("end-of-chat");
    element.scrollIntoView({behavior: "smooth"});
    </script>
    """,
    unsafe_allow_html=True,
)

And here’s how I increment the dummy variable in Python:

st.session_state['dummy_counter'] += 1

I insert a unique <div id="end-of-chat"></div> after each chat message and intend to use this as an anchor to scroll down to. The dummy variable change is triggering the rerun correctly, but it seems the Javascript isn’t executing or having an effect each time.

Despite these measures, after a certain number of messages, new messages aren’t scrolled into view and are instead off-screen.

Is there something in the way Streamlit handles Javascript that could be preventing the desired scrolling behavior?

The dummy variable needs to be inside the Javascript.

Thank you mathcatsand. exactly what I was looking for.

Did you achieve it? I tried all examples I can find and none work. Crazy that such a functionality is not implemented in chat_messages.

2 Likes

This topic was automatically closed 365 days after the last reply. New replies are no longer allowed.