Overflow: one row, or wrap
Some rows must not grow: a tab bar, a header's nav links, a toolbar. When the
entries stop fitting, there are only two honest answers — wrap onto another
line, or keep one row and hide the surplus behind a ⋯ menu.
semantic-ui implements the second as one shared behaviour rather than once per component. Any container can opt in, including one you build yourself.
Live — two headers, identical extras. The frame is kept narrow on purpose:
at full width everything fits and there is nothing to see. The first header
wraps onto a second line, the second keeps one row and collapses the rest
into ⋯.
Opting in
The nodes that have a row to protect expose it as a field:
| Node | Field | Values |
|---|---|---|
section | tabOverflow | WRAP (default) · MENU |
header | extrasOverflow | WRAP (default) · MENU |
UiSection.of("tabs", null).tabOverflow(UiSection.TabOverflow.MENU);
UiHeader.of("Acme").extrasOverflow(UiHeader.ExtrasOverflow.MENU);
WRAP is the default on purpose. It needs no JavaScript, so it is also what
server-rendered pages do — and a wrapped row is never unusable, just taller.
Using it on your own container
The behaviour is driven by data attributes, not by node type, so it works on anything you render:
<div class="my-toolbar" data-sui-overflow="menu">
<button>Bold</button>
<button>Italic</button>
…
</div>
| Attribute | Meaning |
|---|---|
data-sui-overflow="menu" | Opt in. Any other value is left alone. |
data-sui-overflow-items="<selector>" | Which children may move. Default: all element children. A tab bar sets .sui-tab so its own ⋯ control is never eaten. |
data-sui-overflow-active="<class>" | When a moved child carries this class, the ⋯ button gets it too — so a hidden-but-selected entry stays visible. Default active. |
The event bus wires this on every mount and on DOM changes, so there is nothing to call. If you render outside the bus, call it yourself:
import { wireOverflow } from "/sui/renderer.js";
wireOverflow(); // idempotent; safe after every re-render
How it decides
On first run and on every resize the behaviour pulls everything back into the row, measures, then moves children from the end into the dropdown until it fits.
The container must be start-aligned. Overflow past the start edge is not
scrollable, so scrollWidth would equal clientWidth and the measurement would
always conclude "it fits" — the menu would stay empty forever. justify-content: flex-end on an overflow container is therefore a silent bug; push the row to
the right with the parent's layout instead.
This cost an hour when the header was built, which is why it is written down.
See also
section— tab bars.header— the nav-links case, plus what else a header drops on a narrow screen.- Mobile & responsive — the other responsive mechanics.