Problem
Long option labels are painted outside the popup background instead of being contained by it. A consumer that adds truncate to the item content gets the same overflow rather than an ellipsis, so there is no way to opt out from the outside.
This is easy to miss with English demo labels and shows up immediately with longer ones (German compounds hit it constantly).
Root Cause
ComboboxItem sizes its content column with grid-cols-[1rem_1fr] (combobox.tsx#L213). 1fr resolves to minmax(auto, 1fr), so the track cannot shrink below the item's min-content width.
The popup frame is clamped — max-w-(--available-width) min-w-(--anchor-width) — but the track inside it is not. When the content is wider than the frame, the frame stops growing and the text keeps going, so it renders next to the background rather than inside it.
Reproduction
Self-contained, no JS framework needed — the frame is pinned at 220px and the positioner variables are hardcoded:
<style>
.frame { position: relative; display: flex; width: 220px; max-width: 220px;
border: 1px solid #d4d4d8; border-radius: 8px; background: #fff; }
.list { display: flex; flex: 1 1 0%; flex-direction: column; padding: 4px; }
.item { display: grid; grid-template-columns: 1rem 1fr; align-items: center;
gap: 8px; padding: 4px 16px 4px 8px; }
.body { grid-column-start: 2; }
</style>
<div class="frame">
<div class="list">
<div class="item"><span></span><span class="body">Gefahrgutbeauftragtenbescheinigung</span></div>
</div>
</div>
Measured in the browser, frame width 222px including the border:
| Item |
Text width |
Painted outside the frame |
Ellipsised |
| as shipped, single long word |
243px |
yes |
no |
as shipped, consumer adds truncate |
313px |
yes |
no |
with minmax(0, 1fr) |
164px |
no |
yes |
The second row is the one that surprised us: adding truncate to the item content does not help, because the track's auto minimum still reserves the full min-content width.
Solution
Give the content track an explicit zero minimum:
- grid-cols-[1rem_1fr]
+ grid-cols-[1rem_minmax(0,1fr)]
No other change is needed — the consumer's truncate then behaves as expected, and items without it wrap instead of overflowing.
Same pattern elsewhere
The identical track appears in three more item components:
Environment: @base-ui/react 1.6, Tailwind 4.1.5.
Problem
Long option labels are painted outside the popup background instead of being contained by it. A consumer that adds
truncateto the item content gets the same overflow rather than an ellipsis, so there is no way to opt out from the outside.This is easy to miss with English demo labels and shows up immediately with longer ones (German compounds hit it constantly).
Root Cause
ComboboxItemsizes its content column withgrid-cols-[1rem_1fr](combobox.tsx#L213).1frresolves tominmax(auto, 1fr), so the track cannot shrink below the item's min-content width.The popup frame is clamped —
max-w-(--available-width) min-w-(--anchor-width)— but the track inside it is not. When the content is wider than the frame, the frame stops growing and the text keeps going, so it renders next to the background rather than inside it.Reproduction
Self-contained, no JS framework needed — the frame is pinned at 220px and the positioner variables are hardcoded:
Measured in the browser, frame width 222px including the border:
truncateminmax(0, 1fr)The second row is the one that surprised us: adding
truncateto the item content does not help, because the track'sautominimum still reserves the full min-content width.Solution
Give the content track an explicit zero minimum:
No other change is needed — the consumer's
truncatethen behaves as expected, and items without it wrap instead of overflowing.Same pattern elsewhere
The identical track appears in three more item components:
select.tsx#L181drawer.tsx#L531drawer.tsx#L603Environment:
@base-ui/react1.6, Tailwind 4.1.5.