Ensuring Auto-Scroll to Bottom in a Chat Application with Streamlit Popovers

I’m building a chat application using Streamlit, and I’m using st.popover to contain the chat interface. However, I’m struggling with ensuring reliable auto-scrolling to the bottom of the chat message list when new messages are added. Here’s my setup:

import streamlit as st

# Custom CSS for styling the popover and chat messages
st.markdown("""
<style>
.stPopover > div[data-testid="stPopoverContent"] {
    width: 400px !important;
    max-width: 80vw !important;
    height: 600px !important;
    max-height: 80vh !important;
    display: flex;
    flex-direction: column;
}
.chat-messages {
    flex-grow: 1;
    overflow-y: auto;
    padding: 10px;
    background: #f9f9f9;
    border: 1px solid #ddd;
    border-radius: 5px;
}
.chat-input {
    position: sticky;
    bottom: 0;
    background-color: white;
    padding: 10px;
    border-top: 1px solid #e0e0e0;
    z-index: 10;
}
</style>
""", unsafe_allow_html=True)

# JavaScript to scroll to the bottom
scroll_script = """
<script>
    setTimeout(() => {
        const container = window.parent.document.querySelector('.chat-messages');
        if (container) {
            container.scrollTop = container.scrollHeight || 999999;
        }
    }, 200);
</script>
"""

# Initialize chat history
if "messages" not in st.session_state:
    st.session_state.messages = []

# Chat popover
with st.popover("💬 Chat Assistant", use_container_width=True):
    # Div for messages with scrolling
    st.markdown('<div class="chat-messages">', unsafe_allow_html=True)
    
    # Display chat messages
    for message in st.session_state.messages:
        with st.chat_message("user" if "user" in message else "assistant"):
            st.markdown(message)
    
    st.markdown('</div>', unsafe_allow_html=True)
    
    # Div for input with sticky positioning
    st.markdown('<div class="chat-input">', unsafe_allow_html=True)
    
    # Input area
    if prompt := st.chat_input("Type your message here..."):
        st.session_state.messages.append(f"You said: {prompt}")
        
        # Inject scroll script to ensure bottom is visible
        st.markdown(scroll_script, unsafe_allow_html=True)
        
        # Refresh to update chat
        st.experimental_rerun()
    
    st.markdown('</div>', unsafe_allow_html=True)

# Ensure scroll script runs
st.markdown(scroll_script, unsafe_allow_html=True)