Welcome to Vanilla Breeze
This bell pulls live notifications from /go/notify/messages — the same contract documented at /docs/concepts/service-contracts/. Static articles like this one are the no-JS / no-backend fallback.
This bell pulls live notifications from /go/notify/messages — the same contract documented at /docs/concepts/service-contracts/. Static articles like this one are the no-JS / no-backend fallback.
Immersive reading shell with scroll and paged modes. Wraps long-form content with a chrome bar, page navigation, font controls, and column picker.
| 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. |
reader-view degrades gracefully at every layer:
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>
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>
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>
Any element inside slot="chrome" can trigger behaviour via data-reader-action:
| Action | Effect |
|---|---|
toggle-mode | Toggle between scroll and pages |
set-mode-scroll | Switch to scroll mode |
set-mode-pages | Switch to pages mode |
font-increase | Increase font size one step |
font-decrease | Decrease font size one step |
set-columns | Set columns from data-reader-value |
prev-page | Previous page |
next-page | Next page |
| 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 |
Active in pages mode only:
| Key | Action |
|---|---|
| ArrowRight / Space / PageDown | Next page |
| ArrowLeft / PageUp | Previous page |
| Home | First page |
| End | Last page |
role="toolbar" with aria-label="Reading controls"aria-pressed<output> with aria-live="polite"role="region" and aria-label="Article pages"prefers-reduced-motion: reducedata-prose on the article — this enables hyphenation from the native article styles.storage-key for multiple instances — each reader needs its own localStorage key. Authored attributes (mode, columns) take precedence over persisted state.<layout-columns> — The column flow surface that reader-view wraps<layout-text> — Vertical rhythm container (simpler, no columns)<text-reader> — Text-to-speech reader (different use case)