Buttons Within a Class Don't Trigger When a Key is Added

The problem is that you use a key with a randomly generated value. This randomly generated value will (except by random chance) be different every time the script reruns. Streamlit will have no way of providing continuity between reruns. I generally advise to never use random keys because

  1. you can’t control if something will accidentally be the same by chance when you want it to be different and
  2. you have to be careful that your randomly generated value goes into st.session_state so that it doesn’t change with each rerun before you want it to change.

If you truly need a fresh key every time to force a widget to reset I either have an index that I increment or use a timestamp which is guaranteed to be different each time.

Generally though, you want a widget to be stateful for at least a period of time or for a set of user actions before you reset it, so most often I use an index for dynamically generated widgets where I have complete control over what that index is and when/if I increment or discard it.

I would remove all random generation within your custom class. I would instead pass a key to the class to use to identify that instances widgets. Here is a simplified example of what I mean:

import streamlit as st

if 'results' not in st.session_state:
    st.session_state.results = {}
    st.session_state.step = 0

class Example():
    def __init__(self, options, key):
        def save():
            st.session_state.results[key] = {
                'options': st.session_state[f'{key}_options'],
                'slider': st.session_state[f'{key}_slider']
            }
            st.session_state.step += 1

        st.radio('Options', options, key=f'{key}_options')
        st.slider('Slider', key=f'{key}_slider')
        st.button('Next', on_click=save, key=f'{key}_next')

Example(['a', 'b', 'c'], st.session_state.step)

st.write(st.session_state.results)

And if you want to show them in sequence, you would have a for i in range(st.session_state.step) loop to show each in succession. In that case, I recommend you also add in a parameter to disable the widgets within a particular instance of a class so that only the newest one is clickable.