Skip to main content

reflex-pdfslick

PyPI version Python versions License: MIT GitHub

A native Reflex component that wraps PDFSlick so you can view and interact with PDF documents in pure Python — no HTML, no iframe, no hand-written JavaScript.

PDFSlick is built on top of Mozilla's PDF.js and uses Zustand to expose a reactive store for the loaded document. reflex-pdfslick bridges that store and PDFSlick's imperative API into Reflex's declarative, state-driven model: document state (page number, page count, zoom, rotation, metadata, thumbnails) flows back to Python as events, and Python triggers actions (go to page, zoom, rotate, print, download) on the viewer.

Project status — ALPHA, published on PyPI. The component runtime, imperative controls, and the full 7-example demo gallery are built and covered by tests; the demo compiles to a Reflex production build in CI. See Roadmap for details.

Requirements

Dependency Supported version
Python 3.11 – 3.13
Reflex >= 0.10.0 (tested with 0.10.0)
Node.js 20+ (used by Reflex to build the frontend; CI runs on Node 24)

reflex-pdfslick 0.1.0 requires Reflex 0.10 and drops Python 3.10, matching Reflex's own requires-python >= 3.11. Stay on reflex-pdfslick==0.0.1 if you are pinned to Reflex 0.9.x.

import reflex as rx
from reflex_pdfslick import pdf_slick


class State(rx.State):
    page_number: int = 1
    num_pages: int = 0

    @rx.event
    def on_page_change(self, page: int):
        self.page_number = page

    @rx.event
    def on_document_load(self, num_pages: int):
        self.num_pages = num_pages


def index() -> rx.Component:
    return pdf_slick(
        url="/sample.pdf",
        scale_value="page-fit",
        single_page_viewer=True,
        on_page_change=State.on_page_change,
        on_document_load=State.on_document_load,
        height="700px",
    )


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

Why a native component instead of an iframe?

Embedding a PDF viewer through an iframe or a raw <embed> works, but it is isolated from your app: you cannot react to page changes, drive the zoom from a Python toolbar, or read the document's metadata into your state. Wrapping PDFSlick as a first-class Reflex component means:

  • Reactive state — page_number, num_pages, scale, rotation, is_document_loaded and document metadata are pushed into Reflex state via typed events.
  • Imperative control from Python — go to page, zoom in/out, fit width/page, rotate, switch scroll/spread modes, print and download are exposed as component-level controls.
  • Reusable & versioned — installable with pip, with the npm dependency (@pdfslick/react) pinned for reproducible builds.
  • SSR-safe — PDF.js is browser-only, so the component is wrapped as a Reflex NoSSRComponent and only ever renders on the client.

Installation

pip install reflex-pdfslick
# or, from source
git clone https://github.com/ecrespo/reflex-pdfslick.git
cd reflex-pdfslick
pip install -e .

Reflex installs the underlying npm packages automatically on first run. The component pins @pdfslick/react and pdfjs-dist (which pull in @pdfslick/core and zustand) and imports the required stylesheet @pdfslick/react/dist/pdf_viewer.css for you.

Custom-component packaging (build & publish)

This repository is a reusable Reflex component package: the code lives in custom_components/reflex_pdfslick/ (shipping the PdfSlickWrapper.tsx wrapper and a committed pdfslick.pyi stub), the demo app in pdfslick_demo/, and pyproject.toml carries the reflex-custom-components / reflex-component keywords used to discover it on PyPI.

Reflex 0.10 note: the reflex component init/build/share CLI was removed in Reflex 0.10. Packages are now built with standard Python tooling (uv build) and stubs are generated with Reflex's own stub generator.

# Regenerate the .pyi type stub after changing props/events.
PYTHONPATH=custom_components uv run python -m reflex_base.utils.pyi_generator \
    custom_components/reflex_pdfslick

# Build the wheel + sdist into dist/ and validate the metadata.
uv build
uvx twine check --strict dist/*

# Manual publish (bump the version in pyproject.toml first):
uv publish                         # or: uv run twine upload dist/*

Automated release (GitHub Actions)

Releases are published by .github/workflows/publish.yml when a vX.Y.Z tag that points to a commit on main is pushed:

# 1. Bump `version` in pyproject.toml and `__version__` in __init__.py,
#    update CHANGELOG.md, merge the PR into main.
git checkout main && git pull
git tag -a v0.1.0 -m "reflex-pdfslick 0.1.0"
git push origin v0.1.0

The workflow checks that the tag matches the package version, runs the tests, builds the sdist + wheel and uploads them to PyPI (Trusted Publishing / OIDC, or a PYPI_API_TOKEN repository secret), then creates the GitHub Release.

The built wheel includes the React wrapper (reflex_pdfslick/PdfSlickWrapper.tsx) and the type stub, so rx.asset(...) resolves the wrapper when the package is installed from PyPI — not only in editable mode.

Planned API (summary)

The full contract lives in specs/api/component-api.md.

Prop Type Description
url str Path/URL of the PDF to load.
scale_value str "auto", "page-fit", "page-width", "page-actual" or a numeric string.
single_page_viewer bool Render a single page at a time.
thumbnail_width int Width (px) of generated thumbnails.
remove_page_borders bool Hide page borders.
Event Payload Fired when
on_document_load int (num pages) The document finishes loading.
on_page_change int (page) The current page changes.
on_scale_change float (scale) The zoom level changes.
on_error dict Loading/parsing fails.

Imperative controls (next/previous page, zoom, rotate, print, download) are driven from Python state — see the API spec for the dispatch mechanism.

The pdfslick_demo/ Reflex app mirrors PDFSlick's own example set. Each example is documented in the PRD and task breakdown:

  1. Simple Viewer — basic viewer with prev/next navigation and zoom.
  2. Full Viewer App — toolbar, zoom selector, rotation, scroll/spread modes, document info, search and thumbnails sidebar.
  3. Thumbnails Layout — a grid of page thumbnails as the primary surface.
  4. Horizontal Thumbnails — a horizontal thumbnail strip.
  5. Multiple Documents — several independent viewers on one page.
  6. Load from ArrayBuffer — open a PDF from in-memory bytes.
  7. Error Handling — graceful handling of load/parse errors.

Run the demo:

cd pdfslick_demo
pip install -r requirements.txt
reflex run

Architecture (at a glance)

Python (Reflex app)
  pdf_slick(url=..., scale_value=..., on_page_change=...)
        │  compiles to
        ▼
React Router + Vite (generated by Reflex)
  <PdfSlickWrapper>  ← local .tsx, NoSSR, calls usePDFSlick(url, options)
        │  renders <PDFSlickViewer/> + (optional) thumbnails
        │  subscribes to usePDFSlickStore selectors → emits Reflex events
        ▼
@pdfslick/react → @pdfslick/core → PDF.js (pdfjs-dist) + Zustand store

Because PDFSlick's public surface is the hook usePDFSlick(...) (not a drop-in component) and its thumbnails component uses a render-prop child, the wrapper is a small local .tsx component that calls the hook internally and exposes a clean prop/event API to Python. Full rationale and trade-offs are in specs/technical/architecture.md.

Spec-Driven Design documentation

This project is documented before it is built. The specs/ directory is the source of truth:

Document Purpose
specs/prd/pdfslick-component.md Product requirements, goals, scope, examples.
specs/technical/architecture.md Technical design, SSR strategy, wrapper pattern.
specs/api/component-api.md Public Python API: props, events, controls.
specs/data-model/store-schema.md PDFSlick store schema and Python ↔ JS mapping.
specs/plans/implementation-plan.md Phases, milestones, sequencing.
specs/tasks/task-breakdown.md Granular, trackable task list per phase.
specs/research/pdfslick-and-reflex-research.md Primary-source research notes that ground the design.

Roadmap

  • Phase 0 — Foundation & SDD: repository, packaging, SDD artifacts, README, demo skeleton.
  • Phase 1 — Core wrapper: PdfSlickWrapper.tsx, pdf_slick component, props, CSS import, NoSSR.
  • Phase 2 — Events & state bridge: page/scale/load/error/metadata events.
  • Phase 3 — Imperative controls: navigation, zoom, rotation, modes, print, download (declarative command prop + commands helpers).
  • Phase 4 — Thumbnails & multi-document: vertical/horizontal thumbnails, independent multi-instance viewers.
  • Phase 5 — Demo gallery (all 7 examples) & docs polish.
  • Phase 6 — Tests & CI: 36 unit tests, GitHub Actions (pytest 3.11–3.13, TSX transpile, demo build smoke on Node 24). Demo compiles to a Reflex production build.
  • Release — 0.0.1 (Reflex 0.9) and 0.1.0 (Reflex 0.10) on PyPI; tag-driven publish workflow.

Credits

This wrapper is an independent project and is not affiliated with or endorsed by the PDFSlick authors.

License

MIT © Ernesto Crespo

Metadata

Release files for reflex-pdfslick 0.1.0

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

Source distribution (sdist)

Source distribution for reflex-pdfslick 0.1.0
File Size Uploaded Provenance Actions
reflex_pdfslick-0.1.0.tar.gz 22.6 kB With provenance Details for reflex_pdfslick-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for reflex-pdfslick 0.1.0
File Interpreter ABI Platform Actions
reflex_pdfslick-0.1.0-py3-none-any.whl Python 3 none any Details for reflex_pdfslick-0.1.0-py3-none-any.whl

Total release size: 40.1 kB

Release files / reflex_pdfslick-0.1.0.tar.gz

Download URL reflex_pdfslick-0.1.0.tar.gz
Size 22.6 kB
Tags Source
SHA-256 checksum
How to use checksums
87c2d9d625e80955d66845f8aba355e80fd9408df9a3137bf0336b119e53d1cd
BLAKE2b-256 checksum
How to use checksums
3504132b16a7e88674f90c0d866b70607e8250293216cb852eeb4a48f33e1167
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

Release files / reflex_pdfslick-0.1.0-py3-none-any.whl

Download URL reflex_pdfslick-0.1.0-py3-none-any.whl
Size 17.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
da5d35ad4b467ef60a4edaa0dda87eef5b7cb2e4f3fb70ccb1334df06f5e1e3c
BLAKE2b-256 checksum
How to use checksums
0aab02b06d9fe44b6a064c660ce27e82ee3b6a86d4340fde7cabba97057573fd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

Security for reflex-pdfslick 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for reflex_pdfslick-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 25, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

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