Prevent the Component from Remounting on Prop Change

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

Slider with key

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)

Duplicate Key error

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

Two sliders

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!