How to Keep Streamlit Chat Input and Button Fixed at Bottom of Page?

Hello, I’m developing a chat application with Streamlit and I want the user input field and the send button to be fixed at the bottom of the page. However, currently, when a user sends a message, the input area and button are not at the very bottom of the page but just above the message. How can I ensure that these elements remain fixed at the bottom of the page even when scrolling? Here is the relevant part of my code:

python
# CSS to fix the input box and buttons at the bottom
st.markdown("""
    <style>
    .fixed-bottom {
        position: fixed;
        bottom: 0;
        left: 0;
        width: 100%;
        background-color: white;
        padding: 10px;
        border-top: 1px solid #ddd;
        display: flex;
        justify-content: center;
        align-items: center;
        z-index: 9999;
    }
    .text-input {
        flex: 1;
        padding: 10px;
        margin-right: 10px;
        border-radius: 5px;
        border: 1px solid #ddd;
    }
    .btn {
        padding: 10px;
        border-radius: 5px;
        background-color: #f0f0f0;
        border: 1px solid #ddd;
        cursor: pointer;
        width: 40px;
        height: 40px;
        display: flex;
        justify-content: center;
        align-items: center;
    }
    .btn-icon {
        background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABTUlEQVQ4T9WTTUoDQRSGn5mYhmDoo4QXgiIo7+BgsiBoeAI8gCH8Av4Cc4gIIZIggJJ4EUtLA+4QvYBxeYi5cmzPvEGJs7A/N2ds7s7DvdnHg7hKp3uDgWGbAot9awNQH4l04aGM2vQBtRNmGEPLQbGFynKsZgmS5cAql4lPjDCTocTXQCTPxOXQDbAkcCJoDqx5ukEu4BlwnfNN3YoUeIlG1cZK3wqCpQrsQRsoxfQZPIvZ8qP2HIn5RbmCB99CAUyIxSAI1J/A5Mj3A9rO4hncPFTMLBqkD35DCPFEYgj+ndlfPQyAizIg6C1AqsFlMxxQ4VAV8Hs1qvDJW+dQtR1pnbYUyN5kQddcfWSu+g3O0mWoBD+Of4EFZyTSvhq8uZPtYFiv/L4isQtmcivgH6Sfhs4wKxDHYNe95QTmSAAAAAElFTkSuQmCC') no-repeat center center;
        background-size: contain;
        width: 24px;
        height 24px;
        border: none;
        cursor: pointer;
    }
    </style>
    """, unsafe_allow_html=True)

input_container = st.container()
with input_container:
    st.markdown('<div class="fixed-bottom">', unsafe_allow_html=True)
    if "prompt" not in st.session_state:
        st.session_state.prompt = ""
    col1,  col3 = st.columns([9, 1])#col2,
    with col1:
        prompt = st.chat_input("Enter your message", key="text_input")
    # with col2:
    #     send_button = st.button("➤", key="send_button", use_container_width=True)
    with col3:
        mic_button = st.button("🎤", key="voice_button", use_container_width=True)
    st.markdown('</div>', unsafe_allow_html=True)

if mic_button:
    st.session_state.is_speaking = True

if st.session_state.is_speaking:
    speech_text = recognize_speech()
    st.session_state.is_speaking = False
    if speech_text:
        st.session_state.prompt = speech_text
        send_message(speech_text)
        st.session_state.prompt = ""

# if send_button:
#     send_message(st.session_state.prompt)
#     st.session_state.prompt = ""

if prompt:
    send_message(prompt)

I just put my entry form BELOW the messages, and when it rerenders, everything related to scrolling looks perfect. The page doesn’t scroll actually, which is desirable, because the new answer just appears and pushes the editor down below it. It’s a very good user experience, relative to how scrolling works.

EDIT: Also trying to go against the way Streamlit lays out components is probably a bad idea too. If the default layouts of things is not sufficient you probably need to be using a different web framework. All this stuff is probably designed to work well on mobile and other environments, and so monkeying with stuff at the level of CSS is just not that great an idea. And whatever you do will likely break in the future, have trouble on different browsers, etc. All the stuff that frameworks like this are designed to solve.

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