New package st-pages: change page names and icons in sidebar without changing filenames

I love multipage apps, but don’t really prefer having to move/rename files in order to change their name, order or icon in the sidebar. I especially don’t like adding emojis to filenames.

I’ve been doing a number of experiments about different ways multipage apps could work differently, and have combined some of those into a new package st-pages.

Example usage:

from st_pages import Page, show_pages, add_page_title

# Optional -- adds the title and icon to the current page
add_page_title()

# Specify what pages should be shown in the sidebar, and what their titles 
# and icons should be
show_pages(
    [
        Page("streamlit_app.py", "Home", "🏠"),
        Page("other_pages/page2.py", "Page 2", ":books:"),
    ]
)

PyPI: st-pages · PyPI
GitHub: GitHub - blackary/st_pages: An experimental version of Streamlit Multi-Page Apps
Example app (basic): https://st-pages.streamlit.app/
Example app (with sections): https://st-pages-sections.streamlit.app/

If you want to give this a try, please do! Feedback is welcome on this post, or on GitHub.

16 Likes

Thanks for adding it to the Tracker :heart:

Also looks awesome, need to try this cough video idea cough !

1 Like

Great addition also gives a tree view look & feel…

Hi @blackary, lovely component!

Just 2 points:

  1. I get a flicker each time a menu option is chosen. I guess it’s due to the streamlit rerun - don’t know if that can be done away with.
  2. Can a separate component be made just for the left pane (menu) with a folding option (i.e. If Cool apps is clicked, the display of menu options ‘Example Four’ and ‘Example Two’ are toggled)? (Hopefully, writing custom Streamlit components will get easier in time).

Cheers

1 Like

@Shawn_Pereira

  1. Yeah, the flicker is unfortunate but unavoidable for now, as I’m just using css to add the indentation, and there’s a slight delay before it actually gets applied to each new page. I’d love to figure out a way to make it permanent.

  2. Yes, that would be nice. For now, this is a fairly thin wrapper around the existing MPA, so that we get the nice url changes, etc. for free. I agree that something like that would be great, but would be tough to get the same url behavior.

2 Likes

This is a great addition, I was able to delete a lot of code by using it. One thing that I’ve noticed is that sometimes when I start my app, the first page isn’t selected and there is no display in the main area of my app. I have to click on the first (or any) icon in the sidebar to see some content.

2 Likes

This should be Streamlit’s default design, it’s so much better, thanks for this package.

1 Like

@rickspada Yeah, I have seen that issue sometimes as well, and haven’t figured out a workaround yet. The good news is that it should work for all future users of the app once it’s loaded the page list once.

1 Like

Thank you, is it possible to make the section also clickable.
Thanks.

Thanks @blackary, this is very cool!

A quick question: how hard would it be to make this per-user with your current codebase? One problem with the official implementation of multi-page apps is that one cannot limit the page visibility depending on the user, which was possible with the old st.radio / st.selectbox multi-page hack, and for a second there I was really excited that this package would solve that.

@Sai_SaiGraph It is definitely possible, but right now the section is just a placeholder, not an actual page. Would you like to be able to specify an actual page of content, or have it be auto-generated somehow?

Hi @ennui, I would love to be able to extend this to be able to dynamically specify the pages that are visible to each user, but haven’t found a clean way to do that yet. I’ll probably keep looking for a way to do that, and am very open to contributions if anyone has any ideas.

1 Like

I m having trouble making sections. Is there any trick? I have tried the code and toml versions, without success. Sections are show, but there is no indentation. The simplest code that replicate this :

from st_pages import Page, Section, add_page_title, show_pages

add_page_title()

show_pages([
    Section(name="Section1", icon=":books:"),
    Page("page1.py", "Page 1", ":notebook:"),
    Page("page2.py", "Page 2", ":blue_book:"),
    Section(name="Section2", icon=":bar_chart:"),
    Page("page3.py", "Page 3", ":bar_chart:"),
])
1 Like

@Rafael_Del_Rey Do you see any error messages while it’s running? What version of st-pages do you have installed? I tried a fresh install of st-pages in a new environment with your code, and it worked for me.

Você sabe se é possível adicionar icons de outras fontes?

Hi @blackary , is it possible to put two emojis side by side for the page icons?

@mmazzarino Right now only unicode icons are supported (though if someone has a clever idea for supporting other sources of icons, I would love it), either by pasting them in directly, or with the :icon-name: syntax.

Hi @DebayanPaul93, it is possible, though with the default styling it doesn’t work very well. If you just paste in two icons, like :house::carrot:, add add the following line to all your pages, it seem to work fine:

st.markdown(
    """
<style>
    [data-testid="stSidebar"] span:first-child { {
        width: initial !important;
    }
</style>
    """,
    unsafe_allow_html=True,
)

If others are interested in this behavior, I could also bake this into the library, but I don’t know if it’s a very common use-case.

Hi @blackary , Thanks for the hack! I will test it out. My use case in the multi-page apps is that it puts a checkmark emoji next to the existing emoji when the user provides all required inputs in that page to indicate that page has been filled. My app is basically collection a lot of user inputs in multiple pages and doing a heavy calculation at the final page of the app. I wanted to inform the user before they proceed to calculation step, all required inputs are provided else they can check the page where inputs are missing.

Hi @DebayanPaul93, ah, that is a very interesting idea. Unfortunately, this library is not currently well-suited for dynamically updating the page list or icons on a per-user basis. Because it simply piggy-backs on the existing Streamlit behavior, which is to maintain a global cache of pages in the app, if one user changes the list of pages, or their appearance, it will change for all users. I am very interested in solving the general problem of dynamically altering the page list on a per-user basis, but I don’t have a great way to do it yet.