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

# Specify what pages should be shown in the sidebar, and what their titles 
# and icons should be
        Page("", "Home", "🏠"),
        Page("other_pages/", "Page 2", ":books:"),

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

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


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).


1 Like


  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.


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.


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 @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.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


    Section(name="Section1", icon=":books:"),
    Page("", "Page 1", ":notebook:"),
    Page("", "Page 2", ":blue_book:"),
    Section(name="Section2", icon=":bar_chart:"),
    Page("", "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:

    [data-testid="stSidebar"] span:first-child { {
        width: initial !important;

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.