dequelabs / dequelabs/cauldron
Toast: `overflow-y: auto` on `.Toast__message-content` shows a spurious scrollbar for any toast containing a Link
- Dominant language
- TypeScript
- Stars
- 127
- Forks
- 31
- Avg merge
- 2d 12h
- Merged PRs (30d)
- 8
Description
## Summary
Since 7.0.0, `.Toast__message-content` has `overflow-y: auto` and a viewport-based `max-height`. Any `Toast` whose body contains a `Link` (or another inline element whose ink extends below the line box) now renders a **vertical scrollbar** even though the content visibly fits. On Linux — e.g. CI screenshot runners — the scrollbar draws with ▲▼ stepper arrows.
Plain-text toasts are unaffected. This regressed between 6.25.2 and 7.x.
## Screenshots
### Before
### After
## Environment
- `@deque/cauldron-react` / `@deque/cauldron-styles` **7.2.0** (introduced in 7.0.0)
- Chromium (any) — most visible where classic, non-overlay scrollbars are used (Linux)
- Font size `--text-size-small` (15px), the Toast default
## Steps to reproduce
Minimal, self-contained (`minimal-repro.html`, loads styles from unpkg):
```html
×
const el = document.querySelector('.Toast__message-content')
console.log(el.clientHeight, el.scrollHeight, el.scrollHeight > el.clientHeight)
// 17 19 true -> overflows by 2px -> scrollbar
```
Or with the React component:
```jsx
{}}>
Catch more issues with Pro. Try for free, no payment required!
```
## Expected
A toast whose content fits should not display a scrollbar.
## Actual
A vertical scrollbar appears next to the dismiss button. `scrollHeight` (19px) exceeds `clientHeight` (17px) by ~2px.
> _Screenshots of the banner with and without the scrollbar are available and can be attached — the minimal repro above logs `clientHeight=17 scrollHeight=19 overflows=true`, which is the underlying signal._
## Root cause
`.Toast__message-content` was made a scroll region:
```css
.Toast__message .Toast__message-content {
border-top: 4px solid transparent;
border-bottom: 4px solid transparent;
overflow-y: auto; /* added in 7.x */
max-height: calc(100vh - var(--top-bar-height) - 2 * var(--space-smallest)); /* added in 7.x */
}
```
The box reserves no room for ink that legitimately paints **below the line box** — a `Link`'s underline stroke (and descenders). At `--text-size-small`, `line-height: normal` computes to ~17px with only ~2px of slack below the baseline; the underline needs slightly more, so Chromium reports ~2px of vertical scroll overflow and `overflow-y: auto` surfaces a scrollbar.
Notes:
- The `max-height` (~full viewport) is **not** the trigger — it only matters for a genuinely oversized toast. The scrollbar appears on 1–2 line toasts far below `max-height`.
- The `4px solid transparent` top/bottom borders look like an attempt to reserve breathing room, but **borders sit outside the content box and don't count toward scroll overflow**, so they don't prevent this. They currently only serve to host the focus underline (`:focus → border-bottom-color`).
- At larger font sizes the bug disappears, because `line-height: normal` scales up and the slack becomes sufficient — consistent with the diagnosis.
## Suggested fixes (in order of preference)
**1. Reserve room for the ink (minimal).**
```css
.Toast__message .Toast__message-content { padding-bottom: var(--space-quarter); }
```
Smallest change; preserves the cap-and-scroll behavior; no effect on plain toasts; no focus-style changes. Verified to remove the false scrollbar while a genuinely oversized toast still scrolls.
**2. Make the intended breathing room real (proper fix).** The transparent top/bottom borders were evidently meant as breathing room but are invisible to overflow. Convert them to padding (so they count toward the content box) and re-home the focus underline off `border-bottom-color` onto `text-decoration` / `box-shadow` / `outline`. Fixes the underlying miscalculation rather than padding around it.
**3. Loosen the line box.** `line-height: ~1.4` on `.Toast__message-content` contains the ink and scales across font sizes, but visibly changes toast vertical rhythm.
**Please avoid** `overflow: clip` / `overflow-clip-margin` as a quick fix — it hides the scrollbar but also disables scrolling for genuinely oversized toasts, silently removing the 7.x behavior.
## Verification
Measured `clientHeight` / `scrollHeight` on `.Toast__message-content` (Playwright, Chromium):
| Content | client / scroll | Scrollbar |
| --- | --- | --- |
| Link, 1 line | 17 / 19 | yes |
| Link, wrapped | 34 / 36 | yes |
| Plain text, wrapped | 34 / 34 | no |
| Link + `padding-bottom: var(--space-quarter)` | 36 / 36 | no |
Contributor guide
Research direction
Search the styles for `.Toast__message .Toast__message-content` and reproduce the issue with the provided minimal HTML or Toast example. Verify in Chromium that fitting Link content has no vertical scrollbar, while genuinely oversized toast content still scrolls; also confirm plain-text toasts remain unaffected.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- css, react
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100