accessible-books-in-browsers

Github project page

About

Transform EPUB into a series of HTML files for reading directly in the browser, with built-in Media Overlays support too.

By default, the converter splits a content document containing several chapters into one page per chapter at its table of contents entries. Use --no-split-chapters to preserve the source content documents as pages. Heading-based page titles are also on by default; use --no-heading-titles to turn them off. Multiple top-level entries always identify chapters; nested entries are used as chapter boundaries only in long content documents (at least 50 KiB), so ordinary chapter files are not split into their subsections.

See an example fileset):

After conversion, the original EPUB is rewritten as:

Media Overlays conversion adds the following:

Latest

September 2026

See Reading features and Keyboard shortcuts below.

Demos

These demos were created using this conversion script.

Test books:

Reading features

Search works within one book. Results link to the exact passage, including narration cue targets when a book has synchronized audio. The reader loads search-data.json and builds its in-memory index only after the first search.

Narrated results use the existing ids required by their timing cues. Other results use Web Annotation-style TextQuoteSelector anchors: the passage’s exact text plus nearby prefix and suffix context. The reader resolves the quotation after loading the page, so search does not add generated ids to publication content.

Search uses Intl.Segmenter to split text into words according to its language, including scripts such as Chinese, Japanese, Thai, Lao, Khmer and Burmese that do not put spaces between every word. When a browser lacks Intl.Segmenter, the fallback splits on Unicode whitespace and punctuation and adds overlapping two-character pieces for Han, Hiragana, Katakana and Hangul text.

Matching ignores case and Unicode compatibility differences such as full-width forms and ligatures. Combining marks remain significant because they are part of letters in Indic scripts, Vietnamese and many other languages. Two explicit language rules ignore optional Arabic harakat and tatweel, and Hebrew niqqud; new exceptions belong in the small rule table in search-text.js, with the language-specific reason documented there.

The final query word can match a prefix. One-character typo tolerance applies only to words of at least five characters written entirely in Latin, Cyrillic or Greek letters, where an edit is less likely to change a vowel sign or tone mark. Search does not currently stem words or ignore accents in Latin-script languages. Accurate lang markup in the publication improves word segmentation, case folding, display direction and screen-reader pronunciation.

Keyboard shortcuts

Shortcut Where it works What it does
Escape Anywhere, only while the “Skip past” notification is showing Skip past the current table, list, figure, sidebar, footnote, endnote, or note during narration playback
[ Anywhere outside a text field or open popover Previous phrase, continuing onto the previous page from the first phrase of a page
] Anywhere outside a text field or open popover Next phrase, continuing onto the next page from the last phrase of a page
\ Anywhere outside a text field or open popover Play / pause
Alt+Shift+P Anywhere outside a text field or open popover Go to narration position: moves focus, and a screen reader, to the phrase narration is on, e.g. to read on from there after pausing
Alt+Shift+R Anywhere outside a text field or open popover Play from here: starts narration at the phrase that has focus (a screen reader’s cursor brings focus with it) or at selected text
Alt+Shift+L Anywhere outside a text field or open popover Announce the listening time left in the current chapter and book
Alt+Shift+Q Anywhere outside a text field or open popover Announce the current print page
Unassigned While narration is on a phrase containing a note reference Go to the note in this phrase, or open its list of notes
Unassigned After following Go to note Back to text at the exact reference and narration position
Shift+[ / Shift+] Anywhere outside a text field or open popover Previous / next page
Shift+\ Anywhere outside a text field or open popover Caption mode on or off
Alt+Shift+C Anywhere outside a text field or open popover Open the table of contents
Alt+Shift+F Anywhere outside a text field or open popover Open search
Alt+Shift+G Anywhere outside a text field or open popover Open Go to page
Alt+Shift+S Anywhere outside a text field or open popover Open Settings
Alt+Shift+O Anywhere outside a text field or open popover Open About this publication
Alt+Shift+, / Alt+Shift+. Anywhere outside a text field or open popover Narration slower / faster
Alt+Shift+- / Alt+Shift+= Anywhere outside a text field or open popover Smaller / larger text
↑ ↓ ← → Anywhere outside a form control or open popover, only while Caption mode is on Same as [ / ] (on a page without narration, steps through its text)

The narration keys are unmodified single keys. An earlier version used Ctrl+Alt combinations, and screen reader users reported clashes with their assistive technology’s commands (e.g. JAWS/NVDA table-navigation keys). The narration slider uses the usual slider keys (arrows, Page Up/Page Down, Home/End); on the full-book timeline they move by the amounts described under Reading features.

Open Settings, then choose Change keyboard shortcuts to open the shortcut editor. Choose Change next to an action and press its new key, with any modifiers. Escape cancels a change. If another action already uses the key, the editor shows and announces a warning before asking you to confirm the move. Remove clears an action’s shortcut; Restore default restores one action, and Reset to defaults restores the table above. Choices are shared across books on the same website and remembered when you return.

On a Mac, Alt is Option. Escape closes an open panel. The panel, narration position, speed and text size keys use Alt+Shift because NVDA, JAWS, Narrator and VoiceOver don’t use it with letters or punctuation, and Chrome, Edge and Safari don’t use these letters with it; Shift+, and Shift+. would have clashed with NVDA’s and JAWS’s browse-mode commands. Escape stays reserved for Skip past; Tab (including Shift+Tab), Enter and Space are reserved for using controls. The editor warns when a key is also a screen reader browse-mode command (an unmodified letter or some punctuation, or Shift+, and Shift+.). Caption mode’s arrow keys remain fixed.

More about [, ] and \:

The hardware media keys are separate from these: play/pause plays and pauses, and previous/next track move to the previous or next page.

Reading without JavaScript

Every page is a complete HTML page. Without JavaScript, it has a plain header with a Contents button (the table of contents opens without JavaScript, as a native popover) and links to the previous and next pages, and narrated pages have the browser’s own audio player at the bottom. The reading interface’s toolbars only appear when its script runs.

Development