dequelabs / dequelabs/cauldron

Toast: `overflow-y: auto` on `.Toast__message-content` shows a spurious scrollbar for any toast containing a Link

Open Beginner friendly
#2,468 0 comments 0 reactions 0 assignees View on GitHub
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






Catch more issues with Pro.
Try for free, no payment required!


×

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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.