Using HTML in widget labels (e.g., FontAwesome icons + st.button)


I’d like to use FontAwesome icons in labels of widgets to produce, for example, a button with a trash icon.

The script below;

import streamlit as st

st.write('<link rel="stylesheet" href=""/>', unsafe_allow_html=True)

st.write('<i class="fa-solid fa-trash"/>', unsafe_allow_html=True)

st.button('<i class="fa-solid fa-trash"/>')

produces the following:


Inspecting the produced HTML page, I see that < and > are replaced by &lt; and &gt; respectively. If I change these back (in the browser inspection tool), I end up with this


How can I get this working from Python?


I made this solution, without creating a new component, according to this discussion

import streamlit as st
import streamlit.components.v1 as components
import json 

key_dict = {}
st.write('<link rel="stylesheet" href=""/>', unsafe_allow_html=True)

def generate_key(icon, button_key):
    key_dict[button_key] = icon
    return {'label':button_key,'key':button_key}

st.button(**generate_key('<i class="fa-solid fa-circle-user fa-bounce"></i>',button_key = 'button_test_1'))
st.button(**generate_key('<i class="fa-brands fa-youtube fa-spin-pulse"></i>',button_key = 'button_test_2'))

icon_config = f"""
            var elements = window.parent.document.getElementsByClassName('css-x78sv8 eqr7zpz4');
            let dict = {json.dumps(key_dict)};
            let keys = Object.keys(dict);
            let icons = Object.values(dict);
            for (var i = 0; i < elements.length; ++i) {{
                for (var j = 0; j < keys.length; ++j){{
                    if (elements[i].innerText == keys[j])
                    elements[i].innerHTML = icons[j];
components.html(f"{icon_config}", height=0, width=0)

The idea is to first generate a button with a unique key, then search for it and replace its content with the icon

1 Like