Navigation counters
components specs/components/nav-counters.kmd
Async-loaded count badges on navigation/tab items (e.g. "Issues 42", "Pull requests 7") that load in parallel and render together so the nav never reflows item-by-item. Defines the loading contract and the no-layout-thrash rule. Modeled after GitHub Primer UnderlineNav counters.
Quando esta spec se aplica
Triggers primários
- Implement async counter badges on tabs/nav
Todos os triggers
- Add live counts to tabs or a nav bar (Issues/PRs/Notifications)
- Load tab counters asynchronously without the nav jumping around
Corpo da especificação
Component — Navigation counters
Status: v0.1.0 — Draft. Promoted from the GitHub Primer parity scan (meta/docs/stack #092). Source: https://primer.style/components/nav-list (UnderlineNav counters).
R1 — What it is
A counter is a small numeric badge attached to a nav/tab item reflecting a
live count for that destination. It reuses the visual of
specs/components/badges.kmd (numeric variant) but adds an async load
contract (R2–R3) specific to navigation.
R2 — Load in parallel, render together
- All visible counters load concurrently (one batched request where the API allows), not sequentially per tab.
- They render together in a single layout pass once resolved (or on a short ceiling timeout), so the nav reflows at most once — never N times as each count trickles in. This is the core anti-layout-thrash rule (avoids cumulative layout shift).
R3 — Placeholder while loading
- During load, reserve the counter's space with a
specs/components/skeleton.kmdplaceholder (or a fixed min-width slot) so item widths do not jump when numbers arrive. - On error, the counter is simply omitted (the tab still works); failure of one counter never blocks the others or the nav.
R4 — Zero and large values
- A count of zero renders no badge (absence, not "0") unless the surface explicitly wants to show zero.
- Large counts are abbreviated per
specs/components/badges.kmd(e.g.5k+), with the exact value in the accessible name + title.
R5 — Freshness
- Counters are a hint, not a transaction: they may be cached/eventually consistent. Re-fetch on tab focus / surface revisit, not on a tight poll.
R6 — Accessibility & i18n
- The count is part of the tab's accessible name ("Issues, 42 items"), not
an orphan number; the badge itself is
aria-hiddenwhen the name already includes it. - The loading placeholder is not announced as content.
- Number formatting + abbreviations localize per
specs/i18n/contract.kmd(locale digit grouping; "k"/"mil" etc.).
Não-escopo
- The badge visual itself (
specs/components/badges.kmd). - The tab/nav structure & selection (
specs/components/tabs.kmd,specs/components/navigation.kmd). - Real-time push updates of counts (separate; this is load-time + on-focus).
Referências
specs/components/tabs.kmdspecs/components/navigation.kmdspecs/components/badges.kmdspecs/components/skeleton.kmdspecs/i18n/contract.kmd