PDF viewer - how to achieve reactive layout?

Summary

Hello Streamlit community, I’m trying to render a PDF file in my Streamlit app, but I can’t find a way to make the layout reactive.
If I don’t specify width and height in the iframe, the rendered PDF is too small; if I hardcode them like in the code below, I can optimise them for my laptop, but the rendering won’t look nice on other screens. Is there a way to make the frame fit to the max width of the column?

Steps to reproduce

Code snippet:

st.set_page_config(page_title="pdf-GPT", page_icon="📖", layout="wide")
st.header("pdf-GPT")

def clear_submit():
    st.session_state["submit"] = False


def displayPDF(uploaded_file):
    
    # Read file as bytes:
    bytes_data = uploaded_file.getvalue()

    # Convert to utf-8
    base64_pdf = base64.b64encode(bytes_data).decode('utf-8')

    # Embed PDF in HTML
    pdf_display = F'<iframe src="data:application/pdf;base64,{base64_pdf}" width="700" height="100" type="application/pdf"></iframe>'

    # Display file
    st.markdown(pdf_display, unsafe_allow_html=True)


with st.sidebar:
    openai_api_key = st.text_input("OpenAI API Key", key="file_qa_api_key", type="password")
    
    uploaded_file = st.file_uploader(
        "Upload file", type=["pdf"], 
        help="Only PDF files are supported", 
        on_change=clear_submit)


col1, col2 = st.columns(spec=[2, 1], gap="small")


if uploaded_file:
    with col1:
        displayPDF(uploaded_file)
    
    with col2:
        question = st.text_input(
            "Ask something about the article",
            placeholder="Can you give me a short summary?",
            disabled=not uploaded_file,
            on_change=clear_submit,
        )

        if uploaded_file and question and not openai_api_key:
            st.info("Please add your OpenAI API key to continue.")

        if uploaded_file and question and openai_api_key:
            st.info("Answer")

Expected behavior:

Ideally, the rendered PDF should use the max width of column1

Actual behavior:

Without hardcoding width & height:

With hardcoding width & height (can be optimised for a specific screen layout, but this won’t be a universal solution):

p.s. here the link to the GitHub repo: GitHub - andreaxricci/pdf-GPT: Extract information from a PDF file via a conversational agent

Hi @andreaxricci

This video by Andrej Baranovskij shows how to retrieve the UI width that can be used to set the width of Streamlit app elements. In his video he is using the width to set the column width, which you can adapt to your use case.

Hope this helps!

Best regards,
Chanin

Many thanks for the reply, Chanin. This helps partially.

By default, the component now gets to fill dynamically the whole space, as shown in the following example:

…but if I manually resize the window (e.g., I make it smaller), the component doesn’t get automatically resized:

Any chance to reach full responsiveness?

Thanks in advance,

Andrea

P.S. for reference, I’m adding below the relevant snippets of the code I’m using

[...]
from streamlit_javascript import st_javascript

[...]

def displayPDF(upl_file, ui_width):
    # Read file as bytes:
    bytes_data = upl_file.getvalue()

    # Convert to utf-8
    base64_pdf = base64.b64encode(bytes_data).decode("utf-8")

    # Embed PDF in HTML
    pdf_display = f'<iframe src="data:application/pdf;base64,{base64_pdf}" width={str(ui_width)} height={str(ui_width*4/3)} type="application/pdf"></iframe>'

    # Display file
    st.markdown(pdf_display, unsafe_allow_html=True)

[...]

col1, col2 = st.columns(spec=[2, 1], gap="small")


if uploaded_file:
    with col1:
        ui_width = st_javascript("window.innerWidth")
        displayPDF(uploaded_file, ui_width -10)

    with col2:
        [...]

just setting the width to width="100%" in the html injection does the magic for me. PDF iframe is always the same widths as the column - and resizes accordingly when I resize the window