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.
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)
“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
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?
Thanks for stopping by! We use cookies to help us understand how you interact with our website.
By clicking “Accept all”, you consent to our use of cookies. For more information, please see our privacy policy.
Cookie settings
Strictly necessary cookies
These cookies are necessary for the website to function and cannot be switched off. They are usually only set in response to actions made by you which amount to a request for services, such as setting your privacy preferences, logging in or filling in forms.
Performance cookies
These cookies allow us to count visits and traffic sources so we can measure and improve the performance of our site. They help us understand how visitors move around the site and which pages are most frequently visited.
Functional cookies
These cookies are used to record your choices and settings, maintain your preferences over time and recognize you when you return to our website. These cookies help us to personalize our content for you and remember your preferences.
Targeting cookies
These cookies may be deployed to our site by our advertising partners to build a profile of your interest and provide you with content that is relevant to you, including showing you relevant ads on other websites.