Vanilla Breeze

Highlights & Annotations

Medium-style text highlighting with private notes — engine, selection toolbar, action components, and persistence layer.

Overview

Vanilla Breeze ships a Medium-style highlighting system: select text, pick a color, optionally add a private note. Highlights persist in localStorage per page. Notes live in a panel that opens when you click the margin annotation, and the storage layer is a single private object behind a controller — easy to export, import, or wire to a sync backend later.

The system is layered. Each layer has one job and you opt into the layers you want.

The four layers

LayerWhat it doesHow you use it
Engine
data-highlights attribute
src/utils/highlights-init.js
Range serialization, persistence, CSS Custom Highlight API rendering (with <mark> fallback), margin annotations, public mutation API. Emits highlights:added, highlights:removed, highlights:clicked, highlights:request-note, highlights:selected. <article data-highlights> on any container. Without other layers it renders read-only stored highlights and exposes the controller API.
Selection toolbar
<selection-menu>
Floating toolbar that appears when a user selects text in a target element. Composes action children. Detects selection, positions itself, dismisses on outside click / Escape. <selection-menu for="article-id">…</selection-menu> with action children inside.
Highlight action
<highlight-wc>
Inside <selection-menu>: icon button + color palette dropdown that commits a highlight via the engine. Standalone: HTML-first sugar that turns a target into a data-highlights container. Inside selection-menu: <highlight-wc colors="red,green"></highlight-wc>. Standalone: <highlight-wc for="article-id"></highlight-wc>.
Note action + panel host
<note-wc>
Inside <selection-menu>: highlight + open note panel in one click. Anywhere on the page: hosts the note panel UI for any highlight that requests one (margin-annotation clicks, programmatic openFor()). <note-wc></note-wc> as a selection-menu child, OR placed once on the page so margin annotations have a panel to open.

Recipes

Read-only display of stored highlights

Just the engine, no UI. Renders highlights persisted under the page's pathname; new selections do nothing.

Full interactive (highlight + notes)

Engine + selection-menu + highlight-wc + note-wc. The 4-line vanilla recipe.

Custom colors

Define --highlight-{name} CSS tokens, then list the names on both data-highlights-colors (engine) and colors (highlight-wc swatches).

Page-tools toggle for notes

Drop a note-wc with for= into the page-tools rail; clicking it opens the note panel for the first highlight on that article.

Events

EventDetailWhen
highlights:added{ id, color, text }A highlight is created via the controller
highlights:removed{ id }A highlight is deleted
highlights:clicked{ id, highlight }The user clicks an existing highlight (Custom Highlight API hit-test, <mark> fallback, or margin annotation)
highlights:request-note{ id, highlight, controller }Margin-annotation click — the convention for opening a note. <note-wc> listens at document level and opens its panel.
highlights:selected{ text, rect }User finishes a selection inside a target. Ignored by <selection-menu> (it has its own listener); useful for power users without selection-menu.

Engine API

The HighlightController instance is returned from initHighlights(element). Each [data-highlights] element has exactly one controller (cached).

Method / propertyPurpose
getHighlights()Snapshot of all highlights (array of { id, color, text, startOffset, endOffset, note })
removeHighlight(id)Delete one
clearAll()Wipe all highlights for this element
exportHighlights()JSON string for backup / sync
importHighlights(json)Replace highlights from JSON
findHighlightRect(id)First viewport rect of a highlight (used by note-wc to align its panel)
colorsActive color names
elementThe owning DOM element

Internal mutation methods _createFromSelection(color), _changeColor(id, color), and _updateNote(id, text) are for action components (highlight-wc, note-wc) and are not part of the documented public API.

Storage

Highlights are written to localStorage under the namespace vb-highlights with a key derived from data-highlights (or the page's pathname when the attribute has no value). Multiple articles on the same page can share a key by setting the same value.

Related