[Python] Streamlit textarea with live byte counter

Discussão em 'Python' iniciado por Stack, Setembro 8, 2025.

  1. Stack

    Stack Membro Participativo

    I have a small problem in my application. I am currently working on a Streamlit app where I generate text via OpenAI. This text is displayed in a textarea for the user, and the textarea has a live byte counter.

    First, I tried creating the textarea using components.html: My code:

    def html_text_area_with_live_byte_counter(label, default_value, key, height=150, max_bytes=2000):
    html_code = f"""
    <div style="font-family: Arial, sans-serif;">
    <label for="{key}" style="font-weight: bold;">{label}</label><br>
    <textarea id="{key}"
    style="
    width: 100%;
    height: {height}px;
    font-size: 16px;
    background-color: #f0f0f0;
    font-family: 'Helvetica Neue', sans-serif;
    line-height: 1.5;
    letter-spacing: 0.5px;
    padding: 10px;
    border: 1px solid #ccc;
    border-radius: 4px;
    color: #333;
    ">{default_value}</textarea>
    <div id="{key}_counterContainer" style="margin-top: 10px;">
    <strong>Byte-Zähler:</strong> <span id="{key}_byteCount">0</span> Bytes von {max_bytes}
    </div>
    </div>
    <script>
    (function() {{
    const textarea = document.getElementById("{key}");
    const byteCountSpan = document.getElementById("{key}_byteCount");
    const counterContainer = document.getElementById("{key}_counterContainer");
    const maxBytes = {max_bytes};
    function updateByteCount() {{
    const encoder = new TextEncoder();
    const byteCount = encoder.encode(textarea.value).length;
    byteCountSpan.innerText = byteCount;
    // Ändert die Farbe des gesamten Byte-Zähler-Textes, wenn der Wert überschritten wird
    if (byteCount > maxBytes) {{
    counterContainer.style.color = "red";
    }} else {{
    counterContainer.style.color = "inherit";
    }}
    }}
    textarea.addEventListener("input", updateByteCount);
    updateByteCount();
    }})();
    </script>
    """
    components.html(html_code, height=height + 100, scrolling=False)


    With this approach, the byte counter updates live while the user types. The problem: I also have a download button that lets the user save the textarea content as a .txt file. If I use the HTML component, I can’t grab the updated text, only the original default value.

    So I switched to a standard Streamlit st.text_area:

    def text_area_with_live_byte_counter(label: str, key: str, default: str = "",
    height: int = 400, max_bytes: int | None = None) -> str:
    # nur beim ersten Mal mit Default befüllen
    if key not in st.session_state:
    st.session_state[key] = default

    st.text_area(label, key=key, height=height)

    val = st.session_state[key]
    count = len(val.encode("utf-8"))
    over = max_bytes is not None and count > max_bytes
    st.markdown(
    f'<div style="margin-top:-6px;color:{ "red" if over else "inherit" }">'
    f'<strong>Byte-Zähler:</strong> {count} Bytes{f" von {max_bytes}" if max_bytes else ""}'
    f'</div>',
    unsafe_allow_html=True
    )
    return val



    Here the counter only updates after the user leaves the textarea. I know that Streamlit’s textarea is static, but isn’t there a way to make the byte counter update live while typing?

    So in the end, I need a textarea with a live byte counter that can also be accessed by Streamlit in order to generate a download button from its content.

    This is my first question ever asked here, so if more information is needed, I’ll be happy to provide anything necessary to help find a solution.

    Continue reading...

Compartilhe esta Página