Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/johnfactotum/foliate-js/llms.txt

Use this file to discover all available pages before exploring further.

This guide walks you through building a minimal but fully functional e-book viewer. By the end you will have a page that opens an EPUB, tracks the reader’s position with the relocate event, and responds to prev() and next() navigation calls. The same setup works for all supported formats — MOBI, AZW3, FB2, CBZ, and PDF — because view.js detects the file type automatically.
foliate-js requires a web server. ES modules cannot be loaded from file:// URLs. Use any static file server during development.
1

Add foliate-js as a git submodule

There is no npm release yet. The recommended way to include foliate-js is as a git submodule, which lets you pin to a specific commit and pull updates on your own schedule.
git submodule add https://github.com/johnfactotum/foliate-js
This clones the library into a foliate-js/ directory at the root of your project. Commit the .gitmodules file and the submodule reference alongside your other code.
2

Serve your project with a web server

Start any static file server from your project root. Here are two common options:
python3 -m http.server 8080
Open http://localhost:8080 (or whatever port your server uses) in your browser. Do not open HTML files directly via file:// URLs.
3

Import view.js and register the custom element

In your JavaScript module, import view.js. The import registers the <foliate-view> custom element as a side effect — you do not need to do anything else to enable it.
import './foliate-js/view.js'
The file must be in a <script type="module"> tag or imported from another module. Classic scripts do not support ES module syntax.
<script type="module" src="reader.js"></script>
4

Create the element and add it to the DOM

Create the <foliate-view> element programmatically and append it to the document. Style it to fill the viewport or whatever container you want the reader to occupy.
const view = document.createElement('foliate-view')
document.body.append(view)
foliate-view {
  display: block;
  width: 100%;
  height: 100vh;
}
5

Open a book file

Call view.open() with a File object (from an <input type="file">), a Blob, or a URL string. The method detects the format automatically and returns a promise that resolves when the book is ready.
// Open by URL
await view.open('example.epub')

// Open a File object from a file picker
const [file] = fileInput.files
await view.open(file)
view.open() calls makeBook() internally, which inspects the file’s magic bytes to identify the format. Passing a URL causes it to fetch the file first.
6

Listen to the relocate event

The relocate event fires whenever the reader’s position changes — on page turns, after goTo() calls, or when the layout reflows. Its detail object contains the current CFI, fraction, TOC item, and more.
view.addEventListener('relocate', e => {
  const { cfi, fraction, tocItem, pageItem } = e.detail
  console.log(`Position: ${Math.round(fraction * 100)}%`)
  console.log(`CFI: ${cfi}`)
  if (tocItem) console.log(`Chapter: ${tocItem.label}`)
})
Save cfi to persistent storage so you can restore the reader’s position on next load by passing it to view.init().
7

Navigate with prev(), next(), and goTo()

Once a book is open, use these methods to move through it:
// Page navigation
await view.prev()
await view.next()

// Direction-aware navigation (respects RTL books)
await view.goLeft()
await view.goRight()

// Go to a specific location (CFI, href, or section index)
await view.goTo('epubcfi(/6/4!/4/2/1:0)')
await view.goTo('chapter-02.xhtml')
await view.goTo(3) // section index

// Restore a saved position on load
await view.init({ lastLocation: savedCfi, showTextStart: false })

Complete example

Below is a minimal but working reader page that ties all the steps together. It opens a file chosen by the user, tracks position changes, and provides prev/next buttons.
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>E-book reader</title>
  <style>
    body { margin: 0; display: flex; flex-direction: column; height: 100vh; }
    #controls { padding: 8px; display: flex; gap: 8px; }
    foliate-view { flex: 1; display: block; }
  </style>
</head>
<body>
  <div id="controls">
    <input type="file" id="file-input" accept=".epub,.mobi,.azw3,.fb2,.cbz,.pdf" />
    <button id="prev">Previous</button>
    <button id="next">Next</button>
    <span id="position"></span>
  </div>

  <script type="module">
    import './foliate-js/view.js'

    const view = document.createElement('foliate-view')
    document.body.append(view)

    document.getElementById('file-input').addEventListener('change', async e => {
      const [file] = e.target.files
      if (file) await view.open(file)
    })

    view.addEventListener('relocate', e => {
      const { fraction, tocItem } = e.detail
      const pct = Math.round(fraction * 100)
      document.getElementById('position').textContent =
        tocItem ? `${tocItem.label} (${pct}%)` : `${pct}%`
    })

    document.getElementById('prev').addEventListener('click', () => view.prev())
    document.getElementById('next').addEventListener('click', () => view.next())
  </script>
</body>
</html>

Events reference

EventWhen it firesKey detail properties
relocatePosition changescfi, fraction, index, range, tocItem, pageItem
loadA section finishes loadingdoc, index
linkUser clicks an internal linka, href
external-linkUser clicks an external linka, href_
draw-annotationAn annotation needs to be rendereddraw, annotation, doc, range
show-annotationUser clicks an annotationvalue, index, range
MethodDescription
view.open(book)Open a File, Blob, URL string, or book object
view.close()Close the book and release resources
view.init({ lastLocation, showTextStart })Initialize position from a saved CFI or start of text
view.goTo(target)Navigate to a CFI, href, or section index
view.goToFraction(frac)Navigate to a 0–1 fraction of the whole book
view.prev() / view.next()Previous or next page
view.goLeft() / view.goRight()Direction-aware navigation (handles RTL books)
EPUB books can contain JavaScript that runs in your page’s origin. You must configure Content Security Policy before using foliate-js in production. See the security guide for details.

Build docs developers (and LLMs) love