Description
Allow users to define a light/dark theme in their StreamTeX document and switch between themes at runtime via a sidebar toggle, with the selected theme correctly propagated through the entire pipeline: live rendering, HTML export, and PDF export.
Currently, the export pipeline (generate_full_html()) reads theme colors exclusively from st.get_option("theme.backgroundColor"), which reads .streamlit/config.toml — a static file loaded once at server startup. There is no mechanism to override theme colors at runtime for the export.
Problem Analysis
The current theme color resolution chain for the export HTML is:
generate_full_html() → ExportConfig.theme_bg → _get_theme_color() → st.get_option() → config.toml
The PdfConfig at lines 375-376 and 438-439 of book.py reads session_state["_stx_theme_bg"], but this only affects the PDF footer/page-number color — not the HTML body background, which is written inline by generate_full_html() at line 368 of export.py:
f"body {{ font-family: Arial, Helvetica, sans-serif; background: {bg}; color: {text}; }}\n"
This inline style on <body> cannot be overridden by CSS injected via stx.st_html() into the export buffer content, because buffer content is rendered inside <div class="streamtex-page">, which is a child of the <body> that already has the hardcoded background.
What was tried and why it failed
| Approach |
Why it fails |
st.html(css) with Streamlit selectors |
Not in the export buffer at all |
stx.st_html(css) with body { background: #fff !important } |
In the buffer, but buffer content is inside <div class="streamtex-page">, not at <body> level — the inline background on <body> wins |
session_state["_stx_theme_bg"] = "#fff" |
Read by PdfConfig (line 375) but not by generate_full_html() which calls _get_theme_color() → st.get_option() → config.toml |
Modify config.toml at runtime |
Streamlit doesn't reload config.toml without server restart |
Proposed Solution
Minimal fix (2 lines in export.py)
Add session_state lookup in the resolution chain of generate_full_html(), lines 356-358:
# Before (current):
bg = c.theme_bg or _get_theme_color("theme.backgroundColor", "#fff")
text = c.theme_text or _get_theme_color("theme.textColor", "#333")
# After (proposed):
bg = c.theme_bg or st.session_state.get(_STX_THEME_BG_KEY) or _get_theme_color("theme.backgroundColor", "#fff")
text = c.theme_text or st.session_state.get(_STX_THEME_TEXT_KEY) or _get_theme_color("theme.textColor", "#333")
This adds one level of priority: ExportConfig.theme_bg > session_state > config.toml, and is backward-compatible (existing projects that don't set session_state are unaffected).
Full feature (sidebar toggle)
- Add a
theme_toggle: bool = False parameter to st_book()
- When enabled, render a
st.sidebar.toggle("Dark mode") in the sidebar Settings expander (alongside existing toggles like "Wrap All")
- On toggle change, update
session_state["_stx_theme_bg"] and session_state["_stx_theme_text"]
- Apply
sts.theme = dark_overrides or sts.theme = light_overrides for StreamTeX style IDs
- Inject CSS via
stx.st_html() for Streamlit DOM overrides (live rendering)
- With the minimal fix above, the export pipeline automatically picks up the correct colors
Optional: st_book() theme parameter
st_book(
[...],
theme="light", # or "dark", or "auto" (follow config.toml)
theme_toggle=True, # show toggle in sidebar
)
Files to modify
| File |
Change |
streamtex/export.py L356-358 |
Add session_state lookup in generate_full_html() |
streamtex/book.py |
Add theme_toggle parameter, render sidebar toggle, update session_state |
streamtex/book.py L796 |
Optionally pass theme_bg/theme_text to ExportConfig from session_state |
Environment
| Key |
Value |
| StreamTeX |
>=0.3.0 (editable install, dev) |
| Python |
3.10.9 |
| OS |
Darwin 25.4.0 arm64 |
| UV |
0.8.12 |
| Project |
ai4se6d |
| Branch |
main |
| Commit |
4e17082 |
Description
Allow users to define a light/dark theme in their StreamTeX document and switch between themes at runtime via a sidebar toggle, with the selected theme correctly propagated through the entire pipeline: live rendering, HTML export, and PDF export.
Currently, the export pipeline (
generate_full_html()) reads theme colors exclusively fromst.get_option("theme.backgroundColor"), which reads.streamlit/config.toml— a static file loaded once at server startup. There is no mechanism to override theme colors at runtime for the export.Problem Analysis
The current theme color resolution chain for the export HTML is:
The
PdfConfigat lines 375-376 and 438-439 ofbook.pyreadssession_state["_stx_theme_bg"], but this only affects the PDF footer/page-number color — not the HTML body background, which is written inline bygenerate_full_html()at line 368 ofexport.py:f"body {{ font-family: Arial, Helvetica, sans-serif; background: {bg}; color: {text}; }}\n"This inline style on
<body>cannot be overridden by CSS injected viastx.st_html()into the export buffer content, because buffer content is rendered inside<div class="streamtex-page">, which is a child of the<body>that already has the hardcoded background.What was tried and why it failed
st.html(css)with Streamlit selectorsstx.st_html(css)withbody { background: #fff !important }<div class="streamtex-page">, not at<body>level — the inlinebackgroundon<body>winssession_state["_stx_theme_bg"] = "#fff"PdfConfig(line 375) but not bygenerate_full_html()which calls_get_theme_color()→st.get_option()→ config.tomlconfig.tomlat runtimeProposed Solution
Minimal fix (2 lines in
export.py)Add session_state lookup in the resolution chain of
generate_full_html(), lines 356-358:This adds one level of priority:
ExportConfig.theme_bg>session_state>config.toml, and is backward-compatible (existing projects that don't set session_state are unaffected).Full feature (sidebar toggle)
theme_toggle: bool = Falseparameter tost_book()st.sidebar.toggle("Dark mode")in the sidebar Settings expander (alongside existing toggles like "Wrap All")session_state["_stx_theme_bg"]andsession_state["_stx_theme_text"]sts.theme = dark_overridesorsts.theme = light_overridesfor StreamTeX style IDsstx.st_html()for Streamlit DOM overrides (live rendering)Optional:
st_book()theme parameterFiles to modify
streamtex/export.pyL356-358generate_full_html()streamtex/book.pytheme_toggleparameter, render sidebar toggle, update session_statestreamtex/book.pyL796theme_bg/theme_texttoExportConfigfrom session_stateEnvironment