npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@profpowell/epub-reader

v0.1.0

Published

Dependency-free EPUB 3 reader built from vanilla web platform primitives.

Readme

epub-reader

A rudimentary EPUB reader built from vanilla web platform primitives. No build step, no npm dependencies, no frameworks.

Live demo: https://profpowell.github.io/epub-reader/

It ships in two forms:

  1. Appindex.html is a drop-in viewer with file picker, drag-and-drop, and keyboard navigation. It uses Vanilla Breeze (loaded from CDN) for the outer shell styling.
  2. Web component<epub-reader src="book.epub"> can be embedded in any page. See examples/embed.html.

How it works

Three small ES modules under src/:

| File | Responsibility | | --- | --- | | zip.js | Minimal ZIP reader. Parses the central directory; inflates deflate entries via the built-in DecompressionStream. | | epub.js | Parses META-INF/container.xml, the OPF (metadata/manifest/spine), and the EPUB 3 nav document (with NCX fallback). Lazily builds blob: URLs for each resource, rewriting HTML/CSS references so chapter iframes can resolve their assets. | | epub-reader.js | Defines the <epub-reader> custom element — Shadow DOM UI with a TOC sidebar, toolbar, and iframe-rendered content. Intercepts in-book link clicks and keyboard navigation. |

It follows the EPUB 3.3 specification for the package, container, and navigation documents.

Running

Browsers won't load ES modules from file://. Serve the folder over HTTP:

python3 -m http.server 8000
# then open http://localhost:8000/

The app shell shows a "Try a sample" bar populated from samples/demo.json — click any entry to load it without opening a file picker. Deep links work too: ?sample=moby-dick.epub auto-loads on first paint.

Live demo (GitHub Pages)

Pushes to main deploy the app to https://profpowell.github.io/epub-reader/ via .github/workflows/pages.yml. The deploy artifact contains index.html, src/, and the demo sample subset listed in samples/demo.json — the full 163 MB test-fixture set stays in the repo for tests but isn't shipped to Pages.

To add or remove a demo sample, edit samples/demo.json. The next push to main will rebuild the site with the updated set.

The Pages site must be enabled in the repository settings: Settings → Pages → Source: GitHub Actions.

Testing

The samples/ directory contains the full IDPF EPUB 3 sample set (release 20230704). npm test walks every sample through the reader in headless Chromium and asserts that metadata, the spine, and the TOC parse and that the first chapter renders without errors.

npm install
npx playwright install chromium  # once, to fetch the browser binary
npm test

Filter to a subset with --grep, e.g. node tests/run-samples.mjs --grep moby.

Known-failing samples (e.g. interactive bindings that need an unsandboxed iframe) are listed in tests/known-failures.json so they don't make the suite red. If a known-failure sample starts passing the runner reports it as XPASS — remove the entry.

Typechecking

The codebase ships as plain ES modules but is fully annotated with JSDoc types and typechecked via the TypeScript compiler in --checkJs mode. There's no build step — tsc only verifies, never emits.

npm run typecheck

src/epub-reader.d.ts is the consumer-facing declaration file. It augments HTMLElementTagNameMap so TypeScript projects get strong types out of document.querySelector('epub-reader'), plus typed addEventListener overloads for epub-loaded, epub-navigate, and epub-error.

Install

From npm (for use in another project):

npm install @profpowell/epub-reader
import '@profpowell/epub-reader';

Or load directly from a CDN — no install, no bundler:

<script type="module" src="https://unpkg.com/@profpowell/epub-reader/src/epub-reader.js"></script>
<epub-reader src="path/to/book.epub"></epub-reader>

Component API

<epub-reader src="path/to/book.epub"></epub-reader>

Attributes

  • src — URL of an EPUB to auto-load.
  • start — Spine index to open first (default 0).
  • hide-toc — Hide the table-of-contents sidebar by default.
  • allow-scripts — Add allow-scripts to the chapter iframe's sandbox attribute so interactive EPUBs (quizzes, bindings, scripted carousels) run. Off by default. Combining allow-scripts with the reader's default allow-same-origin lets scripts in the chapter reach the parent document — only enable for content you trust.

Methods

  • open(source) — Load from a URL, File, Blob, or ArrayBuffer.
  • close() — Unload and revoke blob URLs.
  • next() / prev() — Move through the spine.
  • goToIndex(i, fragment?) — Jump to a spine index.
  • goToPath(pathOrHref) — Jump to a manifest path (chapter2.xhtml#sec1).

Events (bubble, composed)

  • epub-loaded{ metadata, spineLength, toc }
  • epub-navigate{ index, path, title }
  • epub-error{ error }

Styling

The component uses ::part(toolbar | sidebar | content | iframe | title | progress | toc | overlay) for external theming, and respects Vanilla Breeze tokens (--vb-color-surface, --vb-color-text, --vb-color-primary, etc.) when present.

Known limitations

  • No ZIP64 or encryption. Also no EPUB font obfuscation — obfuscated fonts will fail to render, but the text remains legible.
  • Chapter-based paging only. No pagination within a long chapter; scroll within the iframe to read long sections.
  • No persistence. Reading position, bookmarks, and highlights are not saved.
  • Scripts in EPUB content are disabled (iframe sandbox="allow-same-origin").

Browser support

Requires DecompressionStream (Chrome 80+/Firefox 113+/Safari 16.4+) and native custom elements + Shadow DOM.