Fragments and Containers

I have been using experimental fragments decorators with functions that included st.slider objects - this worked in version 1.35 (@st.experimental_fragment). However I have just upgraded to the latest version of streamlit 1.37 (where the decorator has changed to @st.fragment) and now the code creates an error:

Fragments cannot write to elements outside of their container.

Initially I did not understand the error but with some more digging it turns out that you can not add “slider like objects” to containers created outside of the fragment (in my work flow I define the page layer up front which creates theses issues - this wasn’t obvious to me when reading the docs!).

I made a little worked example where sliders do work within a @st.fragment decorator based one of the streamlit tutorials Create a fragment across multiple containers - Streamlit Docs. Thought this might be useful for anyone else who might be encountering a similar issues. The code works but oddly has an issues in rendering st.title within the fragements (no idea!).

import streamlit as st
import time

st.title("Cats!")

row1 = st.columns(3)
row2 = st.columns(3)
row3 = st.columns(2)

grids = [col.container(height=200) for col in row1 + row2]
grids1 = [col.container(height=400) for col in row3]

if 'slider_status' not in st.session_state:
    st.session_state['slider_status'] = False

if 'first_run' not in st.session_state:
    st.session_state['first_run'] = True

def black_cats(paw_count=4):
    time.sleep(0.5)
    st.title("🐈‍⬛ 🐈‍⬛")
    st.markdown(" ".join(["🐾"]*paw_count))

    # st.slider("Black Paws 1", 0, 10) # <- slider placed here creates an error

def orange_cats(paw_count=4):
    time.sleep(0.5)
    st.title("🐈 🐈")
    st.markdown(" ".join(["🐾"]*paw_count))


@st.fragment
def herd_black_cats(card_a, card_b, card_c):
    st.button("Herd the black cats")
    paw_count = st.slider("Black Paws", 0, 10)
    container_a = card_a.container()
    container_b = card_b.container()
    container_c = card_c.container()
    with container_a:
        black_cats(paw_count)
    with container_b:
        black_cats(paw_count)
    with container_c:
        black_cats(paw_count)



@st.fragment
def herd_orange_cats(card_a, card_b, card_c):
    st.button("Herd the orange cats")
    paw_count = st.slider("Orange Paws", 0, 10)
    container_a = card_a.container()
    container_b = card_b.container()
    container_c = card_c.container()
    with container_a:
        orange_cats(paw_count)
    with container_b:
        orange_cats(paw_count)
    with container_c:
        orange_cats(paw_count)

@st.fragment
def herd_black_cats1():
    st.button("Herd the black cat 1")
    paw_count = st.slider("Black Paws 1", 0, 10)
    black_cats(paw_count)


@st.fragment
def herd_orange_cats1():
    r1 = st.empty()
    r2 = st.empty()
    r3 = st.empty()

    with r2:
        paw_count = st.slider("Orange Paws 1", 0, 10)
    with r3:
        st.button(f"Herd the orange cat 1 with {paw_count} paw prints")
    with r1:
        orange_cats(paw_count) # st.title does not render when called

with grids1[0].container():
    herd_black_cats1()

with grids1[1].container():
    herd_orange_cats1()

with st.sidebar:
    herd_black_cats(grids[0],grids[2], grids[4])
    herd_orange_cats(grids[1], grids[3], grids[5])

    st.button("Herd all cats")
1 Like

Hey @David_Bieber ! Thanks for posting on our forum and sharing this insight. Yes, we have noticed issues where developers make changes to the UI outside of the fragment (specifically to interactive widgets because they can trigger a full rerun breaking the mechanism of the fragment)leading to unexpected results. I appreciate sharing this worked examples.

Curious about the title, what is happening with st.title in fragments? Is this as simple as defining a fragment with st.title in it?

Hi @kmcgrady,

Thanks for your response - I should have mentioned that Streamlit is a great product, great docs and efficient code base! I sometime find myself fighting against the streamlit design philosophy, particularly as the code base grows while keeping the code organized (for instance I defined the page step up front def set_page() which creates issues with fragments). Maybe some design philosophy doc on how to build large streamlit apps / how the code base should be structured would be useful.

In the worked example I have marked up the call to st.title which doesn’t work on my window machine using chrome browser (ie within the fragment, I create an empty container which does not render the title). Not a problem, it is just something I noticed, feels like a bug to me (likely mine).

David

Hi @David_Bieber ! Thanks for all the love. I totally see how a design philosophy document might be helpful here as apps get more complex. When we built Streamlit, we did not expect the amazing use cases people have built. It’s a good problem to have at the very least! I’ll share the feedback with the team.