reader-view

Immersive reading shell with scroll and paged modes. Wraps long-form content with a chrome bar, page navigation, font controls, and column picker.

Attributes

Attribute Values Default Description
mode scroll, pages scroll Reading mode. Reflected from JS state.
columns auto, 1, 2, 3 auto Column count in pages mode.
persist true, false true Persist mode, font size, and columns to localStorage.
storage-key any string vb-reader localStorage key. Override for multiple readers per page.
col-controls true, false true Show/hide column picker in chrome.
font-controls true, false true Show/hide font size buttons in chrome.
reader-title any string auto Chrome bar title. Falls back to first <h1>, then document.title.

Progressive Enhancement

reader-view degrades gracefully at every layer:

  • Without JS — renders as a block element. Content is fully readable as a normal scrolling article.
  • Without CSS — semantic HTML renders in document order.
  • With CSS only — layout-columns reading defaults apply. No page controls.
  • With JS — full paged reading with chrome, font controls, column picker, keyboard navigation, and persistence.

Usage Examples

Minimal

JS automatically wraps content in <layout-columns> and generates the chrome bar:

<reader-view> <article data-prose> <h1>Article Title</h1> <p>Content renders in scroll mode by default. Click Pages for paged reading.</p> </article> </reader-view>

Explicit Configuration

Pre-configure mode, columns, and provide your own <layout-columns>:

<reader-view mode="pages" columns="2"> <layout-columns data-layout-align="justify"> <article data-prose data-drop-cap> <h1>Article Title</h1> <p>Explicit two-column paged layout with justified text and drop cap.</p> </article> </layout-columns> </reader-view>

Custom Chrome

Replace the chrome bar entirely via slot="chrome". Wire buttons with data-reader-action attributes:

<reader-view> <div slot="chrome"> <button data-reader-action="set-mode-scroll">Scroll</button> <button data-reader-action="set-mode-pages">Pages</button> <output data-reader-output="page-indicator" aria-live="polite"></output> </div> <article data-prose> <h1>Custom Chrome</h1> <p>The chrome bar is fully replaceable via slot.</p> </article> </reader-view>

Chrome Actions

Any element inside slot="chrome" can trigger behaviour via data-reader-action:

Action Effect
toggle-modeToggle between scroll and pages
set-mode-scrollSwitch to scroll mode
set-mode-pagesSwitch to pages mode
font-increaseIncrease font size one step
font-decreaseDecrease font size one step
set-columnsSet columns from data-reader-value
prev-pagePrevious page
next-pageNext page

Events

Event Detail When
reader-view:mode { mode: 'scroll' | 'pages' } Mode toggled
reader-view:page { page: number, total: number } Page changes
reader-view:font { size: string, index: number } Font size changes

Keyboard Shortcuts

Active in pages mode only:

Key Action
ArrowRight / Space / PageDownNext page
ArrowLeft / PageUpPrevious page
HomeFirst page
EndLast page

Accessibility

  • Chrome bar uses role="toolbar" with aria-label="Reading controls"
  • Mode buttons reflect aria-pressed
  • Page indicator is an <output> with aria-live="polite"
  • Pager has role="region" and aria-label="Article pages"
  • All animations respect prefers-reduced-motion: reduce
  • Content remains in source order — screen readers read normally

Best Practices

  • Use data-prose on the article — this enables hyphenation from the native article styles.
  • Set storage-key for multiple instances — each reader needs its own localStorage key. Authored attributes (mode, columns) take precedence over persisted state.
  • Prefer auto columns — let the component resolve the best count for the viewport.
  • Position anchoring works automatically — switching modes preserves the reader's position in the content.

Related