Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[tooltip] Closing tooltip when scroll starts vs when scroll stops #1447

Open
sunwrobert opened this issue Feb 15, 2025 · 7 comments
Open

[tooltip] Closing tooltip when scroll starts vs when scroll stops #1447

sunwrobert opened this issue Feb 15, 2025 · 7 comments
Assignees
Labels
bug 🐛 Something doesn't work component: tooltip This is the name of the generic UI component, not the React module!

Comments

@sunwrobert
Copy link

Bug report

Current behavior

Hi, great library! We're using this at OpenSea and using the attachToCursor option to power one of our Collection link hoverables. However, we are noticing issues where if people are scrolling while it's attaching, it can get to a state where it no longer disappears even if the mouse is no longer on the anchor.

https://www.loom.com/share/9608676b8c904397af37d46b059ea9b9

Here's a video showcasing this. I don't have a reproducible example in a sandbox at the moment, but wondering if as a stop gap we could at least expand the Tooltip behavior to close if scrolled? Not sure of the best solution here. Thanks!

Expected behavior

Provide a clear and concise description of the expected behavior.

Reproducible example

Link to a CodeSandbox, StackBlitz, or other IDE.

Base UI version

For example v1.0.2

Which browser are you using?

Chrome/Safari/Firefox/Safari iOS etc.

Which OS are you using?

Mac OS/Windows/Other etc.

Which assistive tech are you using (if applicable)?

Voiceover/JAWS etc.

Additional context

Provide any additional context that might help us identify the problem and find a solution.

@sunwrobert sunwrobert added the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label Feb 15, 2025
@atomiks atomiks added component: tooltip This is the name of the generic UI component, not the React module! and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Feb 16, 2025
@atomiks
Copy link
Contributor

atomiks commented Feb 16, 2025

Hi @sunwrobert, attachToCursor isn't a valid option for Base UI's Tooltip (the option is trackCursorAxis) - are you in the right repo? If so, a full reproduction would greatly help

@mj12albert mj12albert added the status: waiting for author Issue with insufficient information label Feb 17, 2025
@sunwrobert
Copy link
Author

Sorry, yeah I meant trackCursorAxis

@github-actions github-actions bot removed the status: waiting for author Issue with insufficient information label Feb 19, 2025
@sunwrobert sunwrobert changed the title [Tooltip] attachToCursor tooltip can sometimes keep following cursor even if not hovering on anchor [Tooltip] trackCursorAxis tooltip can sometimes keep following cursor even if not hovering on anchor Feb 19, 2025
@github-actions github-actions bot added the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label Feb 19, 2025
@mj12albert
Copy link
Member

mj12albert commented Feb 19, 2025

we could at least expand the Tooltip behavior to close if scrolled?

Related: mui/material-ui#38379

We discussed closing the tooltip on scroll start vs stop before but didn't reach a decision yet: https://mui-org.slack.com/archives/C02P87NQLJC/p1732704384238479 CC @colmtuite

Currently it closes when scroll stops which is intentional, the docs demo demonstrates this: https://master--base-ui.netlify.app/react/components/tooltip

@mj12albert mj12albert removed the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label Feb 19, 2025
@mj12albert mj12albert added new feature New feature or request and removed new feature New feature or request labels Feb 19, 2025
@mj12albert mj12albert changed the title [Tooltip] trackCursorAxis tooltip can sometimes keep following cursor even if not hovering on anchor [Tooltip] Closing tooltip when scroll starts vs when scroll stops Feb 19, 2025
@atomiks
Copy link
Contributor

atomiks commented Feb 20, 2025

It looks like this bug (based on the video) extends further than just closing on scroll or not - when the mouse has left the trigger in the provided videos it also doesn't close but should. That would make the bug less problematic

@sunwrobert
Copy link
Author

Yup, the issue is that it still shows even when not on the trigger anymore

@atomiks atomiks added the bug 🐛 Something doesn't work label Feb 21, 2025
@atomiks
Copy link
Contributor

atomiks commented Feb 21, 2025

I set up a basic CodeSandbox for you to edit - I wasn't able to reproduce the bug in the video under the most basic scenario.

https://codesandbox.io/p/sandbox/dazzling-bardeen-gsmvft

More info about the prop settings, potential CSS styles that could cause issues, etc., would help

As for a workaround, making it controlled and manually adding an onMouseLeave to close it might fix it?

@sunwrobert
Copy link
Author

Here's the source:

"use client"
import { Tooltip as TooltipPrimitive } from "@base-ui-components/react/tooltip"
import React, {
  ComponentProps,
  ComponentPropsWithoutRef,
  ElementRef,
  forwardRef,
} from "react"
import {
  TooltipVariantProps,
  tooltipVariants,
} from "../../styles/utils/tooltip"
import { classNames } from "../../utils"
import { Text } from "../Text"

export const TooltipLabel = forwardRef<
  ElementRef<typeof Text.Label>,
  ComponentPropsWithoutRef<typeof Text.Label>
>(function TooltipLabel({ className, children, ...rest }, ref) {
  return (
    <Text.Label
      asChild={true}
      className={classNames("normal-case", className)}
      ref={ref}
      size="xs"
      {...rest}
    >
      <p>{children}</p>
    </Text.Label>
  )
})

export type TooltipProps = Pick<
  ComponentProps<typeof TooltipPrimitive.Root>,
  "open" | "defaultOpen" | "onOpenChange" | "delay" | "hoverable"
> &
  Pick<
    ComponentProps<typeof TooltipPrimitive.Positioner>,
    | "align"
    | "side"
    | "alignOffset"
    | "sideOffset"
    | "anchor"
    | "className"
    | "style"
  > &
  TooltipVariantProps & {
    /**
     * Trigger content
     */
    children: React.ReactNode &
      ComponentPropsWithoutRef<typeof TooltipPrimitive.Trigger>["render"]
    /**
     * Content to render in the portal.
     */
    content: React.ReactNode

    /**
     * Whether to disable the Tooltip from opening.
     */
    disabled?: boolean

    /**
     * Whether to disable pointer events on the Tooltip.
     * We need to apply classes to [data-radix-popper-content-wrapper] to make this work.
     * NOTE: this automatically disables portals
     */
    disablePointerEvents?: boolean

    /**
     * This will make the tooltip stick to the cursor as it moves.
     */
    attachToCursor?: boolean
  }

/**
 * A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.
 */
export const TooltipBase = forwardRef<
  ElementRef<typeof TooltipPrimitive.Popup>,
  TooltipProps
>(function TooltipBase(
  {
    open,
    defaultOpen,
    onOpenChange,
    content,
    children,
    className,
    disabled,
    delay = 200,
    hoverable,
    align = "center",
    variant = "default",
    alignOffset = 0,
    sideOffset = 8,
    animation = "fade-in",
    disablePointerEvents,
    attachToCursor,
    side = "top",
    style,
    anchor,
  },
  ref,
) {
  if (disabled || !content) {
    return <>{children}</>
  }

  const tooltipClassNames = classNames(
    "border border-level-1 p-2",
    tooltipVariants({ variant, animation }),
    className,
  )

  return (
    <TooltipPrimitive.Root
      defaultOpen={defaultOpen}
      delay={delay}
      hoverable={hoverable}
      open={open}
      trackCursorAxis={attachToCursor ? "both" : undefined}
      onOpenChange={onOpenChange}
    >
      <TooltipPrimitive.Trigger render={children} />
      <TooltipPrimitive.Portal>
        <TooltipPrimitive.Positioner
          align={align}
          alignOffset={alignOffset}
          anchor={anchor}
          className={classNames(
            "z-tooltip",
            disablePointerEvents ? "pointer-events-none" : undefined,
          )}
          side={side}
          sideOffset={sideOffset}
        >
          <TooltipPrimitive.Popup
            className={classNames(tooltipClassNames, className)}
            ref={ref}
            role="tooltip"
            style={style}
          >
            {content}
          </TooltipPrimitive.Popup>
        </TooltipPrimitive.Positioner>
      </TooltipPrimitive.Portal>
    </TooltipPrimitive.Root>
  )
})

export const Tooltip = Object.assign(TooltipBase, {
  Label: TooltipLabel,
})

const fadeInClassNames = classNames(
  "animate-in fade-in",
  // Handling both Tooltip and Popover states for convenience
  "data-[state=closed]:animate-out data-[state=closed]:fade-out",
  // For base-ui components
  "data-[closed]:animate-out data-[closed]:fade-out",
)

export const tooltipVariants = tv({
  base: classNames("z-tooltip rounded-lg border border-level-1 outline-none"),
  variants: {
    variant: {
      default: elevatedSurfaceVariants({ variant: "sm" }),
      outlined: outlinedVariants(),
    },
    animation: {
      "fade-in": fadeInClassNames,
      "slide-out": classNames(
        fadeInClassNames,
        "data-[side=top]:slide-in-from-bottom-2",
        "data-[side=right]:slide-in-from-left-2",
        "data-[side=bottom]:slide-in-from-top-2",
        "data-[side=left]:slide-in-from-right-2",
      ),
      none: "",
    },
  },
  defaultVariants: {
    variant: "default",
  },
})

I'll try the controlled workaround and see if that fixes. Thanks!

@oliviertassinari oliviertassinari changed the title [Tooltip] Closing tooltip when scroll starts vs when scroll stops [tooltip] Closing tooltip when scroll starts vs when scroll stops Mar 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🐛 Something doesn't work component: tooltip This is the name of the generic UI component, not the React module!
Projects
None yet
Development

No branches or pull requests

4 participants