Unable to jump to different page of pdf with button and st.markdown

  1. Running locally
  2. Streamlit version: 1.35.0, python 3.12.3

I was trying to create a pdf view with

"""<iframe src="data:application/pdf;base64,{base64}#page={page}" width="550" height="900" type="application/pdf"></iframe>
"""

and it turns out that when the value of page changes with button click, the embedded iframe does not change the page, i.e. does not jump to corresponding page.

Here is a simple code to run to check.

import streamlit as st
import base64


def load_pdf(pdf_file: str):
    with open(pdf_file, "rb") as f:
        return base64.b64encode(f.read()).decode("utf-8")

if 'base64_pdf' not in st.session_state:
    st.session_state.base64_pdf = load_pdf(pdf_example)
if 'page' not in st.session_state:
    st.session_state.page = 0
if 'display_pdf' not in st.session_state:
    st.session_state.display_pdf = f"""
    <iframe src="data:application/pdf;base64,{st.session_state.base64_pdf}#page={st.session_state.page}" width="550" height="900" type="application/pdf"></iframe>
"""

st.markdown(st.session_state.display_pdf, unsafe_allow_html=True)

if st.button('Click me'):
    st.session_state.page = 40
    st.session_state.display_pdf = f"""
    <iframe src="data:application/pdf;base64,{st.session_state.base64_pdf}#page={st.session_state.page}" width="550" height="900" type="application/pdf"></iframe>
"""

You will have to render the iframe again after the button is pressed.

Code
import streamlit as st
import base64
from streamlit.components.v1 import html


def load_pdf(pdf_file: str):
    with open(pdf_file, "rb") as f:
        return base64.b64encode(f.read()).decode("utf-8")


if "base64_pdf" not in st.session_state:
    st.session_state.base64_pdf = load_pdf("paper.pdf")

if "page" not in st.session_state:
    st.session_state.page = 0

if "display_pdf" not in st.session_state:
    st.session_state.display_pdf = f"""
    <embed src="data:application/pdf;base64,{st.session_state.base64_pdf}#page={st.session_state.page}" width="550" height="900" type="application/pdf"></iframe>
"""

html(st.session_state.display_pdf, height=250)

if st.button("Go to page **5**"):
    st.session_state.page = 5
    st.session_state.display_pdf = f"""
    <embed src="data:application/pdf;base64,{st.session_state.base64_pdf}#page={st.session_state.page}" width="550" height="900" type="application/pdf"></iframe>
    """
    html(st.session_state.display_pdf, height=250)

If you want to keep a single PDF view in your webapp, you could use an empty container st.empty - Streamlit Docs