πŸš€ Streamlit Configurator – A Declarative Framework for Streamlit Apps πŸŽ›οΈ

Hello Streamlit community! :wave: I’m excited to introduce Streamlit Configurator – a declarative & modular way to build Streamlit apps. :art: Instead of manually defining every component, you can structure pages effortlessly, while enjoying powerful state management and reusable layouts.

:sparkles: Key Features

:white_check_mark: Declarative Layouts – Use ComponentConfig & PageConfig to structure pages without repetitive code.
:floppy_disk: Robust State Management – Preserve values across page refreshes with PlaceholderValue.
:recycle: Reusable Components – Define UI once and reuse it across multiple pages.
:arrows_counterclockwise: Seamless Integration – Works alongside native Streamlit calls, so you can still use custom functions.


:video_game: Try It Out

:globe_with_meridians: Live Demo: :link: st-configurator.streamlit.app

:computer: Run Locally:

git clone https://github.com/FrunkyLiu/Streamlit-Configurator.git
cd Streamlit-Configurator
streamlit run example/main.py

:hammer_and_wrench: GitHub & Feedback

:pushpin: GitHub: :link: Streamlit Configurator
:e-mail: Contact: :email: Email

I’d love to hear your thoughts! :bulb: Feel free to open an issue or submit a PR if you find a bug, have feature suggestions, or want to contribute. :raised_hands:

Thanks for checking it out! :rocket: Hope Streamlit Configurator makes your development faster & easier! :blue_heart:

3 Likes

@Frunky Looks pretty useful, and will help separate UI config and rendering from business logic. It appears that it eliminates those nasty callbacks.

Can you clarify, if I had multiple page containers, say main_left and main_right, that I can use PageRenderer.render_layout to render the provided config into those page containers? E.g. :

with main_left:
    # Assume we have a list of component configurations.
    PageRenderer().render_layout(main_left_configs)

Thanks!

@asehmi, thanks a lot for your question!

Currently, I don’t recommend directly using PageRenderer().render_layout() to render multiple independent page containers (such as your examples main_left and main_right). Unlike render_page, the render_layout method doesn’t contain page-specific configurations, and directly using it might lead to keyword generation errors.

Instead, I recommend structuring your configurations using the following approach:

main_left_container_config = ComponentConfig(
    component=st.container,
    children=main_left_configs  # main_left_configs: List[ComponentConfig]
)

...

page_config = PageConfig(
    ...
    body=[main_left_container_config, main_right_container_config]
)

Additionally, based on your naming, I suspect you might be looking for the functionality of st.columns . If that’s the case, you could also structure it like this:

main_columns_config = ComponentConfig(
    component=st.columns,
    args=(2,),
    kwargs={"border": True},
    children=[main_left_configs, main_right_configs]  # main_xxx_configs: List[ComponentConfig]
)

To be completely honest, I feel there is still considerable room for improvement in the design of PageRenderer. If you have any specific usage scenarios or suggestions about areas you find particularly awkward, please share them. Your feedback would greatly assist me in refining and improving the design!

Thanks again for your valuable input!

Quick update: I’ve just realized there’s a bug with the suggested approach I provided earlier. Currently, the length of main_left_configs must exactly match the length of main_right_configs, or it will raise an error. :sweat_smile:
I’ll address this issue ASAP.