Alright, hereās an example. You can place your TOC in the sidebar or on the main page, anywhere you want. The only requirement is to use tocās title()
, header()
and subheader()
methods to create your titles. Call toc.generate()
once you have displayed every title, at the very end of your app.
And just in case, make sure you donāt use user inputs to create your titles. Iām using unsafe_allow_html
, so if the end user can change titles somehow by anything he wants, heād be able to execute code on your page.
Source code here
import streamlit as st
class Toc:
def __init__(self):
self._items = []
self._placeholder = None
def title(self, text):
self._markdown(text, "h1")
def header(self, text):
self._markdown(text, "h2", " " * 2)
def subheader(self, text):
self._markdown(text, "h3", " " * 4)
def placeholder(self, sidebar=False):
self._placeholder = st.sidebar.empty() if sidebar else st.empty()
def generate(self):
if self._placeholder:
self._placeholder.markdown("\n".join(self._items), unsafe_allow_html=True)
def _markdown(self, text, level, space=""):
key = "".join(filter(str.isalnum, text)).lower()
st.markdown(f"<{level} id='{key}'>{text}</{level}>", unsafe_allow_html=True)
self._items.append(f"{space}* <a href='#{key}'>{text}</a>")
toc = Toc()
st.title("Table of contents")
toc.placeholder()
toc.title("Title")
for a in range(10):
st.write("Blabla...")
toc.header("Header 1")
for a in range(10):
st.write("Blabla...")
toc.header("Header 2")
for a in range(10):
st.write("Blabla...")
toc.subheader("Subheader 1")
for a in range(10):
st.write("Blabla...")
toc.subheader("Subheader 2")
for a in range(10):
st.write("Blabla...")
toc.generate()