Skip to content

CustomTooltip paints a fixed dark surface but its contents style from the ambient theme #1783

Description

@simihablo

Summary

CustomTooltip paints a fixed dark surface in both light and dark mode, but anything rendered inside it styles itself from the ambient theme. On a light-mode page that means light-theme content on a near-black chip. Any theme-derived colour placed in a tooltip is therefore wrong in one of the two modes, and nothing in the component or the types says so.

The mechanism

src/custom/CustomTooltip/customTooltip.tsx sets the surface from literals, not from the palette:

bgColor = '#141414',        // default parameter
...
tooltip: {
  sx: {
    background: bgColor,
    color: WHITE,
    ...

#141414 and WHITE do not vary with palette.mode, so the chip is dark on every page. But a child element that resolves theme.palette.* gets the page's theme, which in light mode is tuned for a light background. The tooltip is effectively a dark-surface island with no corresponding theme context, and children have no way to know they are on one.

How it surfaced

Found while fixing an unrelated MUI 9 migration in CollaboratorAvatarGroup (#1780). That call site had been passing a surface override through componentsProps, which MUI 9 no longer reads, so the override had been silently dead since the MUI 9 bump. Removing it - the correct fix, since the surface belongs to CustomTooltip and none of the other call sites overrides it - made the inherited dark chip live again, and immediately exposed the real problem:

The <Divider /> inside that tooltip, separating the collaborator's name from the "Open Recents" button, is invisible in light mode. sistent never overrides palette.divider, so it falls through to MUI's mode-dependent defaults (createPalette.js): rgba(0,0,0,0.12) in light and rgba(255,255,255,0.12) in dark. Black at 12% opacity over #141414 is not visible. In dark mode it is fine.

The outlined Button in the same tooltip happens to escape it, because sistent maps primary to Colors.KEPPEL in both modes and that reads acceptably against dark.

That is the shape of the bug: whether a given tooltip looks right in light mode is currently a coincidence of which tokens its content happens to use.

Why this is a component-level defect, not a call-site one

There are 34 <CustomTooltip> usages across 27 files today. Every one of them is exposed the moment its content uses a mode-dependent token; the collaborator tooltip is simply the first with a Divider in it. Fixing it per call site means:

  • each fix is invisible to the next author, so the trap resets every time;
  • the palette lookups look correct in review - theme.palette.divider is exactly what you would write - and only fail visually, in one mode, inside one component;
  • there is no type or lint signal, because nothing distinguishes "inside a tooltip" from anywhere else.

Suggested resolution

Have CustomTooltip establish the theme context its surface implies, rather than only painting the surface - e.g. wrap its content in a ThemeProvider carrying a dark-mode palette (or the sistent dark theme), so palette.divider, text.* and friends resolve against the surface the content is actually on. Then a Divider in a tooltip is correct without the author having to know.

Two details worth settling in that change:

  1. bgColor is a public prop, so a caller can pass a light surface. The context should follow the actual surface rather than being hardcoded to dark, or bgColor should be narrowed.
  2. color: WHITE on the tooltip root is doing the same job by brute force for text only; it should probably fall out of the context rather than being set separately.

Deliberately not in scope: overriding palette.divider globally in sistent's theme. That would change every Divider in every consumer to fix a tooltip.

Interim state

#1780 takes the narrow fix - styling the affected content correctly for the dark surface at that one call site, with a comment linking here - so nothing visibly broken ships while this waits. That call-site workaround should be removed as part of the component-level fix.

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