365. An overflowing tab strip pages from its ends
Date: 2026-09-17
Status
Accepted. Closes book/src/TODO.md’s “A tab strip scrolls, and has no chevrons at
either end”. Adds ScrollController.position() and onChange, and a
CHEVRON_START mark.
Context
A tab strip’s headers sit in a horizontal viewport (ADR-0118), so a strip wider
than its window can be reached by the wheel or by dragging the thumb. A tab bar
conventionally also has a chevron at each end. The TODO entry named what was
missing: a chevron “needs to know it is at an edge, which is scrollIntoView’s
missing question again”. A ScrollController could move a viewport but could not
say where it was.
Decision
A controller reports its viewport’s position and says when it changes, and a
tab list that overflows puts a tab-pager at each end that pages through it.
ScrollController.Positionholds the offsets, the overflows and the viewport’s size, withoverflowsX(),canScrollLeft()andcanScrollRight().position()answersNONEwith nothing attached.onChange(Runnable)sets a single listener, because a controller has one owner.ScrollStatenotifies it when the offset moves (by any route) and when its measured extents change.TabsStatelistens and keeps the last position.TabListbuilds[rule, pager, viewport, pager]while the headers overflow and[rule, viewport]otherwise.- A pager pages by 80% of the viewport’s width, never less than 40px, through the
controller, so the move glides (ADR-0363). It is
:disabledat the edge it would page past, is aBUTTONnamed “Earlier tabs” or “Later tabs”, and is not a Tab stop: the strip is one stop, and a selected tab already reveals itself. Box.Mark.Kind.CHEVRON_STARTisCHEVRON_ENDmirrored, a kind rather than a transform forCHEVRON_UP’s reason.
Consequences
- The pagers take width from the viewport, so a strip near the threshold has two stable states: overflowing with pagers, or fitting without. Which one it is in depends on the side it was approached from, and it does not oscillate.
gallery-basic-narrowandgallery-icons-narroware re-blessed: their strips overflow and now show pagers.