2025, Sep 22 09:00

Fix st.button Font in Streamlit: Use a Precise CSS Selector to Style the Actual Button Label

Learn why Streamlit st.button font won't change with CSS and how to fix it by targeting the correct DOM element. Use DevTools and override font-family and size.

Styling a Streamlit st.button sounds trivial until the font stubbornly refuses to change. You inject CSS, refresh, even try base64-embedded fonts — and the button text stays the same. The reason is not in caching or iframes. It’s in the actual DOM structure of the button and where the text node lives.

Code example

import streamlit as ui

ui.markdown(
    """
    <style>
    div.stButton > button > div {
        font-family: "Courier New", sans-serif !important;
        font-size: 20px !important;
    }
    </style>
    """,
    unsafe_allow_html=True
)

if ui.button("Click me", use_container_width=True):
    ui.success("Clicked!")

What’s really going on

Inspect the generated HTML with DevTools in Chrome or Firefox and you’ll notice a subtle detail: the visible label of st.button isn’t the button element’s own text. Instead, the text sits inside a p nested in a div, which itself is inside the button. That inner div carries its own font-related styles, so a selector aimed at the button alone doesn’t win the cascade. As a result, CSS like div.stButton > button { font-family: ... } never reaches the actual text node.

This is why approaches like base64 font embedding or cache clearing won’t help when the selector doesn’t target the element that actually renders the text.

The fix

Target the correct level in the DOM where the label is rendered. A selector that reaches into the nested structure overrides the font-family and font-size effectively. In practice, div.stButton > button > div works, and you can go even deeper if needed, such as div.stButton > button > div > p or div.stButton > button p.

Once the selector points at the container wrapping the text, the font updates immediately. No additional hacks, no iframes, no extra components.

Why this matters

UI tweaks in Streamlit often come down to understanding how components are composed in the DOM. If you target the wrong element, the cascade and internal styles will override your rules, and it can look like “Streamlit ignores my CSS.” Knowing how to audit the generated HTML lets you diagnose what’s actually applied and where to override it safely.

Takeaways

If you need a custom font on st.button, it is possible. Inspect the structure with DevTools and aim your CSS at the element that hosts the text. With the right selector, font-family and font-size apply cleanly, and you don’t need workarounds or alternative components to emulate a button.

The article is based on a question from StackOverflow by Fathi Farzad and an answer by furas.