To prevent component remount for interactive widgets, there is a special key
argument to _component_func
that prevents Streamlit from looking at the props to define the identity of the component. This is implemented as a small change in the declaration phase:
__init__.py
import streamlit.components.v1 as components
_component_func = components.declare_component(
"custom_slider",
url="http://localhost:3001",
)
def st_custom_slider(label: str, min_value: int, max_value: int):
component_value = _component_func(label=label, minValue=min_value, maxValue=max_value, key="slider") # Add a fixed key to _component_func
return component_value
With that small addition, the component does not rebuild every time a Python argument is changed. Moreover, the state of the CustomSlider
instance is preserved since the slider is not destroyed — all of which is great news for our interactive slider!
You should not put the key
argument there, though, as Streamlit will find multiple widgets with the same key and won’t be able to manage them.
app.py
import streamlit as st
from streamlit_custom_slider import st_custom_slider
st.title("Testing Streamlit custom components")
label = st.sidebar.text_input('Label', 'Hello world')
min_value, max_value = st.sidebar.slider("Range slider", 0, 100, (0, 50))
v = st_custom_slider(label=label, min_value=min_value, max_value=max_value)
# Add a second custom slider, which will share the same key as the first.
v = st_custom_slider(label=label, min_value=min_value, max_value=max_value)
st.write(v)
It’s better to let the user decide on the identity of each component he declares. The best approach is to move the key
argument into the hands of the user, like in Streamlit’s API if you look at its widgets.
app.py
import streamlit as st
from streamlit_custom_slider import st_custom_slider
st.title("Testing Streamlit custom components")
label = st.sidebar.text_input('Label', 'Hello world')
min_value, max_value = st.sidebar.slider("Range slider", 0, 100, (0, 50))
# Lift key parameter up to the wrapper function
v1 = st_custom_slider(label=label, min_value=min_value, max_value=max_value, key="slider1")
st.write(v1)
v2 = st_custom_slider(label=label, min_value=min_value, max_value=max_value, key="slider2")
st.write(v2)
__init__.py
import streamlit.components.v1 as components
_component_func = components.declare_component(
"custom_slider",
url="http://localhost:3001",
)
# Lift key parameter up to the wrapper function
def st_custom_slider(label: str, min_value: int, max_value: int, key=None):
component_value = _component_func(label=label, minValue=min_value, maxValue=max_value, key=key)
return component_value
You may have noticed this is very similar to the key
parameter from Streamlit native widgets.
There we are. We can now build multiple custom sliders with their own internal state and interactive behavior!