Skip to content

Tooltip renders unexpected visible border because border-bottom-width: var(--h) is emitted without a default --h value #10037

@oleksiy-nesterov

Description

@oleksiy-nesterov

Provide a general summary of the issue here

Tooltip in @react-spectrum/s2 appears to generate atomic CSS where border width consumer classes are emitted in normal mode, but the custom property setters that define those widths are only emitted inside @media (forced-colors: active).

This causes the browser to compute a visible border in normal mode when --h is undefined.

Chrome
Image

Safari
Image

🤔 Expected Behavior?

If tooltip borders are only intended for forced-colors, no border-width consumer class should be emitted in normal mode unless the corresponding CSS variable has a safe default.

😯 Current Behavior

A tooltip renders with an unexpected visible bottom border.

In DevTools, the tooltip element has:

border-bottom-width: var(--h);

but --h is not defined.

Chrome then computes border-bottom-width to the initial value medium, which shows up as 3px.

Source

In src/Tooltip.tsx, tooltip border is only defined for forcedColors:

borderWidth: {
  forcedColors: 1
},
borderStyle: {
  forcedColors: 'solid'
},
borderColor: {
  forcedColors: 'transparent'
},

Generated CSS

The built CSS includes always-on consumer classes like:

._kJ8iPYd13 {
  border-top-width: var(--_k);
}
.hXMFGYc13 {
  border-bottom-width: var(--h);
}

But the variable setters are only emitted inside forced-colors rules:

@media (forced-colors: active) {
  ._jlf13 {
    border-style: solid;
  }
  .ilA13 {
    border-color: #0000;
  }
  .-_k_-l_kb13 {
    --_k: 1px;
  }
  .-h_-lhb13 {
    --h: 1px;
  }
}

Outside forced-colors, --h is undefined.

Why this seems wrong

The width consumer class is active outside forced-colors, but its backing variable is not guaranteed to exist outside forced-colors.

That means the computed value becomes invalid and the browser falls back to the initial value for border-bottom-width, which produces a visible border.

💁 Possible Solution

Possible fixes

  1. Provide default values:
borderWidth: {
  default: 0,
  forcedColors: 1,
}
  1. Only emit the border-width classes inside forced-colors.

  2. Emit default setters like:

--_k: 0px;
--h: 0px;

Workaround

This removes the artifact locally:

<Tooltip
  UNSAFE_style={{
    border: 'none'
  }}
>
  Tooltip text
</Tooltip>

🔦 Context

No response

🖥️ Steps to Reproduce

Simple use

Version

1.3.1

What browsers are you seeing the problem on?

Chrome

If other, please specify.

React + Vite

What operating system are you using?

MacOS

🧢 Your Company/Team

No response

🕷 Tracking Issue

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions