Navigation
The family that moves a person around an application. Menu is the first of it, and the one the rest borrow from: the split button already delegates its menu here, and the toolbar will collapse its overflow into one.
One menu bar, one document
Four menus over an editor, wired the way you would wire them: one attribute joins each button to its menu, and everything they do lands on the document underneath. Use them and watch it change.
The whole menu bar is four buttons, four trigger attributes and one array of items each. There is
no keyboard code in this page: Down opens, Up opens at the last item, letters search, Right opens a submenu,
Escape closes one level, Tab leaves — because that is the WAI-ARIA menu pattern and it lives in the component.
The checkable items report their choice and never rewrite your array; the four lines of JavaScript that apply
it are the four you would have written anyway.
Tabs
One panel showing at a time. Write the panels; the strip is drawn from their own labels, so there is no second element to keep in step and no pair of ids to wire together.
Build #4,182 finished eleven minutes ago on main.
Drag the handle at the corner. When the strip runs out of room it scrolls rather than wrapping, and a tab you reach with the arrow keys is brought into view — which is the part that is usually missing.
Three of 1,204 tests are failing, all in the billing suite.
The badge is a property, so it says whatever the application knows. Press the button and watch it change — and watch the strip change with it, because a badge is part of the tab's accessible name.
86.4% of lines, 79.1% of branches.
Up a tenth of a point since the last release.
Four files, 12.8 MB in total.
Kept for thirty days, then removed.
Staging is on #4,182. Production is two builds behind.
Promotion needs a second approval.
Two packages have newer versions.
Neither is a security release.
Who may trigger a build, and from which branches.
This panel has a value, because its label would change in a translated build and the
component would then report a different thing for the same panel.
Not reachable while it is disabled.
The tabs pattern is held together by two ARIA references — a tab points at its panel, the panel points back — and a reference of that kind cannot cross a shadow boundary. That single fact decided the shape of this component: the strip and the region are both drawn inside it, and your panels are slotted into the region, so both ends of every reference are on the same side of the boundary. The three-element design most libraries use would leave those references resolving to nothing, which looks perfect on screen and fails an audit.
Accordion
Sections that open and close — one at a time, or several. Each section is a heading and a panel, and each one works on its own as a disclosure.
Two to three working days to a UK address, and next-day if the order is placed before noon. Delivery options
Anything unworn, within thirty days, in the packaging it arrived in. Start a return
To the EU and to the United States. Duties are shown at checkout rather than on arrival. Countries and duties
Not available yet.
That is the part most implementations get wrong, and it is invisible until somebody tabs into a closed
section and disappears. overflow: hidden hides a panel without closing it; the content is still
focusable, so a keyboard user tabs into a region they cannot see and a screen reader reads a panel the page
says is shut. Every heading here is a Tab stop as well — an accordion is a list of ordinary buttons, and a
user who has reached one expects Tab to take them onward rather than out — with Up, Down, Home and End as a
shortcut on top of that.
Toolbar
A bar of controls that does not break when the window does. Drag its edge: what stops fitting moves into a menu, and keeps working from there — on the paragraph below, which is a real one.
data-bmx-fixed and never collapses, however narrow it gets.
Items collapse from the end, never by size: a bar that reshuffled itself as the window moved would make “the
third button” worthless as a thing to remember. The dividers go with them — a bar that ends in a vertical
line, or a menu that opens with one, is the same fault seen from two sides. What fits is decided by
arithmetic in src/core/toolbar.ts over sizes the component measures from the rendered elements,
which is the only measurement that survives a theme change, a font swap or a density setting.
One browser, three components
A splitter, a breadcrumb and a pagination control doing a single job between them. Choose a folder on the left and both the trail and the rows follow it. Then drag the divider narrower and watch the trail fold its middle away rather than wrap the panel out of shape.
Three components, three separate answers to “there is not enough room”, and they are worth comparing here because the page shows all three at once. The splitter divides what there is and refuses to let either side disappear by accident. The breadcrumb drops its middle and keeps both ends, because the end is where you are standing. The pagination never changes width at all, so the button under your pointer does not move as you use it. A library that answered the question the same way three times would be wrong twice.
Breadcrumb
The trail back out of wherever you are. Drag the edge and watch the middle fold away — both ends stay, because they are the two crumbs that answer the questions a trail is asked.
aria-current="page", which is what tells a screen reader which of these words is where you
are.
A toolbar collapses from the end; a breadcrumb must not, because the end is where you are standing. The
root goes second-to-last and the final crumb survives alone — you may not be able to see the path, but you
can always see your place in it. The separator is a property, so a house style using
› or a middle dot is one attribute rather than a fork.
Pagination
Eight hundred and thirteen records, twenty at a time. Page through it and watch the control's width: it does not change, so the button under your pointer stays where it was.
The naive page window — the current page, some siblings, an ellipsis at each jump — is four items on page
one and seven in the middle, so every button moves as you use it. Here the width is fixed and the window
slides. An ellipsis never stands for a single page either: 1 … 3 4 5 replaces “2” with a
wider symbol offering a jump nobody can take, so the page is drawn instead. Both rules live in
src/core/pagination.ts, where they are arithmetic rather than rendering.
Splitter
Two panes and a divider you can move — by dragging it, or by focusing it with Tab and using the arrow keys. Double-click it to fold the list away, and again to bring it back at the size it had.
A list narrow enough to be useful and wide enough to read. It will not go below 140 pixels, and past sixty more it folds away entirely.
The pane that takes what is left. Drag towards the middle and the divider is pulled onto the halfway mark — the position a reader is usually aiming at, and a surprisingly hard one to hit by hand.
separator reporting its position as a percentage of what the
bounds actually allow, so “40” means something without knowing how wide the panel is. Arrow keys move it
a step, Shift moves it five, Home and End send it to each pane's minimum, and Enter folds or restores.
The drag is pointer capture, exactly as bmx-slider does it: capture keeps a drag alive when
the pointer leaves the divider — past the panel, out of the window, over an embedded map — and releases
itself if the pointer is lost. The offset at which you took hold is carried through the whole drag, which
is why the divider does not jump on the first pixel. Everything else is arithmetic in
src/core/splitter.ts, including what happens when two minimums cannot both fit: the room is
shared out in proportion, so both panes are visibly cramped rather than one being impossible.