What version of daisyUI are you using?
v5.5.19
Which browsers are you seeing the problem on?
Chrome, Safari, Firefox (Blink + WebKit + Gecko all behave the same here).
Describe your issue
A .tooltip placed near the right (or bottom) edge of a scroll container makes the container's scrollWidth larger than its clientWidth, so the user sees a horizontal (or vertical) scrollbar even though nothing in the visible layout is actually overflowing.
This has been reported a number of times before and closed as expected / "no pure-CSS fix possible":
There is a pure-CSS fix that I'd love to propose: contain: layout.
Why it happens
The tooltip text is painted via a ::before (or .tooltip-content child) that lives in the layout permanently — only opacity toggles its visibility. The host is position: relative, so the pseudo's absolutely-positioned box is registered against the host's containing block. Browsers include that box in the scrollWidth/scrollHeight of every scroll ancestor, even though it's not visible and lives outside the host's own border box. Result: a phantom scrollbar whenever a .tooltip sits near the edge of a scroll container.
Proposed fix
/* packages/daisyui/src/components/tooltip.css */
.tooltip {
@layer daisyui.l1.l2.l3 {
@apply relative inline-block;
contain: layout; /* <-- new */
/* …existing rules… */
}
}
contain: layout (MDN) keeps the layout/scroll calculation of the tooltip's descendants local to the host. It does not clip painting — the tooltip still renders outside its host on hover, exactly as it does today. The pseudo simply stops contributing to ancestor scrollWidth/scrollHeight.
This is specifically the concern raised in #326 — "Clipping the tooltip and hide a part of it? I don't think that's a good solution". contain: layout does not clip. Painting is unaffected; only the scroll-extent calculation changes.
Reproduction
Minimal HTML (v5 markup):
<div style="overflow:auto; width:240px; border:1px solid #ccc; padding:8px;">
<button class="btn tooltip tooltip-top" data-tip="A reasonably long tooltip text">
btn
</button>
</div>
Without the fix: the wrapper shows a horizontal scrollbar at rest.
With the fix (.tooltip { contain: layout }): no scrollbar, hover still shows the full tooltip outside the host.
I verified this on the production app where I hit the bug — both <main> and <mat-sidenav-content> reported scrollWidth > clientWidth purely because of .tooltip pseudos near the right edge of a toolbar. Adding .tooltip { contain: layout; } brought scrollWidth === clientWidth while leaving hover behaviour intact.
Caveats considered
contain: layout establishes a new containing block for absolutely-positioned descendants. .tooltip is already position: relative, so it's already that containing block — no positioning change.
- It doesn't affect transforms or the
::after arrow, both of which paint normally.
- Browser support is broad: Chromium, Firefox, Safari ≥ 15.4.
Ask
Happy to send a PR with the one-line change + tests in the playground/docs if you're open to it — could you assign me?
What version of daisyUI are you using?
v5.5.19
Which browsers are you seeing the problem on?
Chrome, Safari, Firefox (Blink + WebKit + Gecko all behave the same here).
Describe your issue
A
.tooltipplaced near the right (or bottom) edge of a scroll container makes the container'sscrollWidthlarger than itsclientWidth, so the user sees a horizontal (or vertical) scrollbar even though nothing in the visible layout is actually overflowing.This has been reported a number of times before and closed as expected / "no pure-CSS fix possible":
tooltipat the edges of the page are causing the page to overflow #326 — "tooltipat the edges of the page are causing the page to overflow"There is a pure-CSS fix that I'd love to propose:
contain: layout.Why it happens
The tooltip text is painted via a
::before(or.tooltip-contentchild) that lives in the layout permanently — onlyopacitytoggles its visibility. The host isposition: relative, so the pseudo's absolutely-positioned box is registered against the host's containing block. Browsers include that box in thescrollWidth/scrollHeightof every scroll ancestor, even though it's not visible and lives outside the host's own border box. Result: a phantom scrollbar whenever a.tooltipsits near the edge of a scroll container.Proposed fix
contain: layout(MDN) keeps the layout/scroll calculation of the tooltip's descendants local to the host. It does not clip painting — the tooltip still renders outside its host on hover, exactly as it does today. The pseudo simply stops contributing to ancestorscrollWidth/scrollHeight.This is specifically the concern raised in #326 — "Clipping the tooltip and hide a part of it? I don't think that's a good solution".
contain: layoutdoes not clip. Painting is unaffected; only the scroll-extent calculation changes.Reproduction
Minimal HTML (v5 markup):
Without the fix: the wrapper shows a horizontal scrollbar at rest.
With the fix (
.tooltip { contain: layout }): no scrollbar, hover still shows the full tooltip outside the host.I verified this on the production app where I hit the bug — both
<main>and<mat-sidenav-content>reportedscrollWidth > clientWidthpurely because of.tooltippseudos near the right edge of a toolbar. Adding.tooltip { contain: layout; }broughtscrollWidth === clientWidthwhile leaving hover behaviour intact.Caveats considered
contain: layoutestablishes a new containing block for absolutely-positioned descendants..tooltipis alreadyposition: relative, so it's already that containing block — no positioning change.::afterarrow, both of which paint normally.Ask
Happy to send a PR with the one-line change + tests in the playground/docs if you're open to it — could you assign me?