Skip to main content

Reflex PDF Viewer + App

This repository includes the source (under /src) for a Python package reflex_pdf that provides both

  • a reusable Reflex custom component package reflex_pdf.components and
  • a standalone Reflex application reflex_pdf_app.apps.

Prerequisites

  • Python 3.10 to 3.13, including pip.

Note: Current Reflex/Pydantic v1 compatibility emits runtime warnings on Python 3.14+, so production deployments should use Python 3.10-3.13.

reflex-pdf.components

A PDF viewer component for Reflex, built on top of react-pdf.

Install

pip install reflex-pdf

Use in your Reflex app

import reflex as rx
from reflex_pdf import Document, Page


class State(rx.State):
    current_page: int = 1
    n_pages: int = 1

    @rx.event
    def load_success(self, info: dict):
        self.n_pages = info.get("numPages", 1)


def index():
    return rx.vstack(
        rx.heading("Reflex PDF preview", size="8"),
        Document.create(
            Page.create(page_number=State.current_page),
            file="https://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf",
            on_load_success=State.load_success,
        ),
    )


app = rx.App()
app.add_page(index)

Add this to your rxconfig.py:

import reflex as rx

config = rx.Config(
    app_name="your_app",
    frontend_packages=["react-pdf@9.1.1"],
)

Standalone app: reflex_pdf_app

Run from the repository root:

python -m reflex_pdf.apps.run_app

This script will:

  1. Prepare runtime directories for Reflex state and build artifacts
  2. Ensure bun is available for Reflex frontend builds
  3. Ensure Node.js is available (>= 22.14.0 in both dev and prod single-port modes)
  4. Start the app in src/reflex_pdf/apps/ using the current Python environment

To prebuild/compile artifacts without starting the server, run (this uses reflex export --no-zip):

python -c "from reflex_pdf.apps.run_app import prebuild; prebuild()"

Run modes:

  • local default: dev mode on frontend 3000 and backend 8000
  • Codespaces default: prod single-port mode on 3000

Environment overrides:

  • REFLEX_RUN_MODE:
    • dev
    • prod-single-port
  • REFLEX_TRANSPORT:
    • websocket
    • polling
  • REFLEX_FRONTEND_PORT and REFLEX_BACKEND_PORT (dev mode)
  • REFLEX_SINGLE_PORT (prod single-port mode)

For Codespaces, single-port mode avoids separate backend tunnel auth for /_event. The launcher defaults REFLEX_TRANSPORT=polling in Codespaces for compatibility with forwarded-port browser sessions.

Backend event endpoint

This app already uses Reflex's built-in backend event endpoint (/_event) for all state updates (for example State.set_pdf_url).

Because /_event is Reflex's internal event transport rather than a FastAPI route, it is not exposed through Swagger/OpenAPI by default.

For MFE-style integration, the host can set the PDF URL from the same browser session in either of these ways:

  1. Initial URL in iframe source query string:
    • https://<viewer-host>/?pdf=<encoded_pdf_url>
  2. Runtime updates via postMessage to the iframe:
iframe.contentWindow.postMessage(
  { type: "reflex-pdf:set-url", url: "https://example.com/file.pdf" },
  "*",
);

Both approaches update only that user session (no separate backend request needed).

Query-string rule: only one parameter is accepted (pdf). If the URL contains more than one parameter, the app shows: "At most one query parameter is supported (?pdf=<url_encoded_pdf_url>). If your PDF URL contains query arguments, URL encode the entire value."

Example that must be encoded:

  • raw (invalid): /?pdf=https://example.com/file.pdf?token=abc&download=1
  • encoded (valid): /?pdf=https%3A%2F%2Fexample.com%2Ffile.pdf%3Ftoken%3Dabc%26download%3D1

The viewer uses a single URL state (pdf_url) for both initialization and runtime updates:

  • ?pdf=... initializes pdf_url when the page loads.
  • postMessage with { type: "reflex-pdf:set-url", url } updates that same pdf_url in-session.

You can customize URL normalization by registering either:

  • a UrlPreprocessor implementation (ABC), or
  • a lightweight hook function.
from reflex_pdf.apps.url_preprocessor import set_url_preprocess_hook

set_url_preprocess_hook(lambda url: url.replace("http://", "https://"))

Reset to default no-op behavior:

set_url_preprocess_hook(None)

For automation/integration testing outside the browser session, you can post the same event with post_pdf_url_event:

from reflex_pdf.apps.event_test_client import post_pdf_url_event

post_pdf_url_event("http://127.0.0.1:3000", "https://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf")

Development

pip install -e .

Metadata

Release files for reflex-pdf 0.0.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Built distribution (wheel)

Table of built distributions (wheels) for reflex-pdf 0.0.4
File Interpreter ABI Platform
reflex_pdf-0.0.4-py3-none-any.whl Python 3 none any Details

Release files / reflex_pdf-0.0.4-py3-none-any.whl

Download URL reflex_pdf-0.0.4-py3-none-any.whl
Size 18.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
36fa3c9609f33c330bb5f36cab5de0dde30d1f176f8eaaef6b04f1f83900f5ac
BLAKE2b-256 checksum
How to use checksums
b24e163c37039dbc1e941403a3976762f5368df6bb483ac733b5ea35398f93e0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.5

Release history Release notifications | RSS feed

This release

0.0.4 This release

1 release file

0.0.3

1 release file

0.0.2

1 release file

0.0.1

1 release file

0.0.0

1 release file

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page