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.
Pagination upscale for any list-shaped container — native ul/ol/table or VB collections like card-list, data-table, layout-grid. Numbered, prev/next, load-more, and infinite styles. Optional URL state.
The data-paged attribute upscales any list-shaped container with pagination — native lists (<ul>, <ol>), tables (<table>, paginates the <tbody> rows), or VB collections (<card-list>, <data-table>, <layout-grid>). One attribute on the container, no per-element wiring; the script slices direct children, hides those outside the active page, and injects a <nav aria-label="Pagination"> sibling with the controls.
<ul data-paged data-paged-size="10"> <li>...</li></ul>
Four data-paged-style values cover the common pagination shapes:
numbered (default)prev-nextload-moreinfiniteIntersectionObserver sentinel auto-loads more when scrolled into view. Best for endless feeds where users scroll without thinking about pages.| Attribute | Default | Notes |
|---|---|---|
data-paged | — | Opt-in (boolean). |
data-paged-size | 10 | Items per page. 0 disables paging (single page covering all items). |
data-paged-page | 1 | Initial page (1-based, user-facing). |
data-paged-style | numbered | numbered · prev-next · load-more · infinite |
data-paged-window | 2 | For numbered: page numbers shown around current before ellipsis kicks in. |
data-paged-controls | after | before · after · both · none |
data-paged-url | — | Opt-in URL search-param name (e.g. page). When set, page state syncs to the address bar via the History API and back/forward navigates. |
The container emits paged:change after each render. Use it for analytics, scroll-restoration, or driving a sibling component.
list.addEventListener('paged:change', (e) => { const { page, size, total, totalPages } = e.detail; console.log(`Page ${page} of ${totalPages}`);});
The pattern that would have been <content-feed> is a recipe over existing primitives plus this attribute. No wrapper component required.
<site-search target="#feed"></site-search> <card-list id="feed" data-paged data-paged-size="20" data-paged-style="numbered" data-paged-url="page"> <article>...</article> <article>...</article> ...</card-list>
site-search handles filtering and highlighting; <card-list> handles template-driven rendering; data-paged handles paging and URL state. Each piece is independently testable and re-composable.
<nav aria-label="Pagination"> with native <button>s — keyboard-navigable by default.aria-current="page".disabled attribute (focusable but not actionable per WAI-ARIA pagination guidance — use aria-disabled if you need them focusable).…) get aria-hidden="true" so screen readers don't announce them.prev-next style includes a live status ("Page N of M") with aria-live="polite".prefers-reduced-motion: no transitions on page change.The script paginates direct children of the host, with one exception: when the host is <table>, it paginates the <tbody> rows instead (so the <thead> and <tfoot> stay visible).
The injected <nav> nodes are placed as siblings of the host, not children — so they don't affect the host's grid / flex layout and don't trip its mutation observer.