I have content in which I need to filter and show in a 400 pixel height container.
When the content is filtered, the user has the option of using a checkbox to highlight the found text in a transcript.
What I’ve found is that when I click on the checkbox which toggles the highlighting behavior, the content, if scrolled, will often change positions. Meaning, the thumb position of the scrollbar will change and the content that was in view is no longer in view.
I’ve been working on a hacky way to find the find the container, then find the scrollbar, find its position, save the position, swap out the content (highlighted or not), then restore the scrollbar position using JavaScript. I’m trying to avoid this very indirect way to manage the scrollbar state.
Below is the current and normal behavior. Its odd, because the scrolling behavior does not always take place.
To demonstrate the behavior search for something such as ‘are’ or ‘speaker’, which is case insensitive. When you toggle the checkbox, the found text will be highlighted. If the scrollbar is 50-75% of the way scrolled down when the checkbox is toggled, the scrollbar may jump and the content that was in view is no longer in view.
- Can I update the contents of the container and control the scrollbar behavior?
- Is there a relatively simple and robust way to find the scrollbar to manage it.
I have JavaScript code that finds the container with the scrollbar but I’m hoping there is a better way. I still have a little more work to control the scrollbar position.
import streamlit as st
import re
# Sample data to mimic session state content
speaker_text = "Speaker 1: Hello, how are you?\nSpeaker 2: I'm fine, thanks!\n".replace("\n", " \n")
speaker_text = speaker_text * 200
speaker_text = "\n".join(f"{i+1:03}: {line}" for i, line in enumerate(speaker_text.splitlines()))
st.session_state.transcription = "This is a sample transcription text."
st.session_state.diarized_transcription = speaker_text
def filter_transcription(transcription, query, highlight):
"""Mock function to filter transcription."""
lower_transcription = transcription.lower() # Convert transcription to lowercase
lower_query = query.lower() # Convert query to lowercase
if query:
# If highlighting is enabled, replace the matches with highlighted text
if highlight:
# Use the original transcription for replacement, not the lowercase version
filtered_content = re.sub(rf"({re.escape(query)})", r"<mark>\1</mark>", transcription, flags=re.IGNORECASE)
else:
filtered_content = transcription
match_count = lower_transcription.count(lower_query)
else:
filtered_content = transcription
match_count = 0
return filtered_content, match_count
def showExpandedContent(override=False):
if ((st.session_state.transcription) or (override == True)):
transcription_content = st.session_state.diarized_transcription
with st.expander("Diarized Transcription"):
# Layout with two columns for input and label
col1, col2 = st.columns([3, 1], vertical_alignment="center") # 3 for input field, 1 for the label (adjust as needed)
with col1:
# Text input for filtering
filter_query = st.text_input("Filter Diarized Transcription", "")
with col2:
# Checkbox for filtering
highlight_filter = st.checkbox("Highlight Matches", value=False, key="highlighter")
# Filter the transcription content based on query
filtered_content, match_count = filter_transcription(transcription_content, filter_query, highlight_filter)
title_text = f"{match_count} matching item(s)" if match_count > 0 else "No matches found"
# Display the match count
st.markdown(f'<div style="height: 100%; display: flex; align-items: flex-end;">{title_text}:</div>', unsafe_allow_html=True)
# Display the filtered content
content_container = st.container(height=400)
with content_container:
st.write(filtered_content, unsafe_allow_html=True)
with st.expander("Transcribed"):
st.write(st.session_state.transcription, unsafe_allow_html=True)
# Call the function to render content
showExpandedContent()