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 trigger onMobile #86

Closed
jozefdrabik opened this issue Feb 15, 2023 · 17 comments
Closed

Tooltip trigger onMobile #86

jozefdrabik opened this issue Feb 15, 2023 · 17 comments
Labels

Comments

@jozefdrabik
Copy link

I would like to ask how does tooltip work on mobile devices? Because when i tried to use it there it does not work. Is there some solution for this to trigger tooltip when user clicks on trigger?

@jackblackCH
Copy link

Also the tooltip only opens when you hover the border, does not work on the surface: E.g here: https://ui.shadcn.com/docs/primitives/tooltip

@codingcodax
Copy link

I would like to ask how does tooltip work on mobile devices? Because when i tried to use it there it does not work. Is there some solution for this to trigger tooltip when user clicks on trigger?

This is a design decision from Radix UI team, see #955 and the answer by Benoît Grélard.
He said:

This is by design. Tooltips are problematic on touch devices because there is no hover interaction, so if it was on tap it would fight with the general button action, or require 2 taps. That's also why tooltips should just be used generally for extra information that isn't mandatory do use your interface.

In case you "need a tooltip" use a popover instead, as they do in their documentation.

@chadryja
Copy link

chadryja commented Feb 1, 2024

tooltip Not work on mobile view

@0xbid
Copy link

0xbid commented Feb 14, 2024

any progress?

@jozefdrabik
Copy link
Author

@0xbid the only solution is described above. So i use Tooltip for Desktop and for tablet and mobile i just change it to popover. Or u can make some own logic instead of using libraries(made one as well).

@Zwyx
Copy link
Contributor

Zwyx commented Mar 12, 2024

To summarise, they are three components:

Tooltip and Hover Card are only meant to be used on desktop. Popover is meant to be used on desktop and mobile.

This is a design choice by the Radix people. I think it wouldn't make sense to change it here at Shadcn-UI 🤔 so I reckon this issue can be closed.

If you need a hybrid solution, which mounts a popover on mobile and a tooltip by default, have a look at this suggestion 😉

@oxuk85
Copy link

oxuk85 commented Mar 28, 2024

Does it continue to make sense to be locked-in to radix for this scenario? I mean the Radix design choices shouldn't limit the capabilities offered by ShadCn.
Would it make sense to look at a better alternative for this case? Similar as how it was done for the carousel component.
I would say the https://floating-ui.com/ offers a great alternative to build something useful and fully configurable.

@jackblackCH
Copy link

jackblackCH commented Apr 10, 2024

To summarise, they are three components:

Tooltip and Hover Card are only meant to be used on desktop. Popover is meant to be used on desktop and mobile.

This is a design choice by the Radix people. I think it wouldn't make sense to change it here at Shadcn-UI 🤔 so I reckon this issue can be closed.

If you need a hybrid solution, which mounts a popover on mobile and a tooltip by default, have a look at this suggestion 😉

I am surprised, that in 2024, we are still trying to differentiate between "desktop", "touch", "pointer down". When do we realize that everything is hybrid? We will never know if a user is touching only and within the next minute using a pointer device on the same screen? Simple example: I am on an iPad with an iPencil, how should the tooltip behave?

Shouldn't responsive components always work consistently on any "device" with and without "touch"? 🙏

@oxuk85
Copy link

oxuk85 commented Apr 10, 2024

To summarise, they are three components:

Tooltip and Hover Card are only meant to be used on desktop. Popover is meant to be used on desktop and mobile.
This is a design choice by the Radix people. I think it wouldn't make sense to change it here at Shadcn-UI 🤔 so I reckon this issue can be closed.
If you need a hybrid solution, which mounts a popover on mobile and a tooltip by default, have a look at this suggestion 😉

I am surprised, that in 2024, we are still trying to differentiate between "desktop", "touch", "pointer down". When do we realize that everything is hybrid? We will never know if a user is touching only and within the next minute using a pointer device on the same screen? Simple example: I am on an iPad with an iPencil, how should the tooltip behave?

Shouldn't responsive components always work consistently on any "device" with and without "touch"? 🙏

I ended up using @floating-ui/react
I found it was used by Radix in a component.

Here is the demo I found and used as the template for my own re-usable component. It works great on touch devices.

https://codesandbox.io/p/sandbox/xenodochial-grass-js3bo9?file=%2Fsrc%2FTooltip.tsx

In case you are curious here is a gist with the component I build:
https://gist.github.com/oxuk85/34e6969d6ec3971f4561d69f26571bb4

@techlism
Copy link

techlism commented Apr 12, 2024

'use client'
import { Button } from "@/components/ui/button"
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from "@/components/ui/tooltip"
import { InfoIcon } from "lucide-react"
import { useState } from "react"
export default function InfoTooltip({information}:{information : string}) {
    const [open, setOpen] = useState(false);
    function handleOpenClose(){
        if(open){
            setOpen(false);
        }
        else{
            setOpen(true);
            setTimeout(() => {
                setOpen(false);
            }, 2500);
        }
    }
    return (
        <>
        <TooltipProvider>
            <Tooltip>
                <TooltipTrigger asChild className="collapse lg:visible xl:visible 2xl:visible">
                    <InfoIcon className="opacity-15 dark:opacity-50 hover:opacity-80 ml-2"/>
                </TooltipTrigger>
                <TooltipContent className="max-w-[40vw] p-2">
                    <p>{information}</p>
                </TooltipContent>
            </Tooltip>
        </TooltipProvider>
        {open && <p className="absolute z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2">
            {information}
        </p>}
        <Button onClick={handleOpenClose} className="bg-transparent lg:collapse xl:collapse 2xl:collapse m-2" variant={'ghost'}><InfoIcon className="opacity-15 dark:opacity-50 hover:opacity-80"/></Button>
        </>
    )
}

This is what I have settled for. I know not the most elegant but mostly works.

@alberduris
Copy link

In case you "need a tooltip" use a popover instead, as they do in their documentation.

This is the correct solution, and it works like a charm. But honestly I don't understand the point of having both the <Tooltip> and the <Popover>. It seems the <Tooltip> can be deprecated in favor of the <Popover>.

@shadcn shadcn added the Stale label Jul 2, 2024
@shadcn
Copy link
Collaborator

shadcn commented Jul 10, 2024

This issue has been automatically closed because it received no activity for a while. If you think it was closed by accident, please leave a comment. Thank you.

@shadcn shadcn closed this as completed Jul 10, 2024
@devotox
Copy link

devotox commented Jul 21, 2024

Here is a tooltip that works on both mobile and desktop. We just handle all interactions ourselves.
We get the added benefit of having this work with tabbing i.e. on a form and using the Enter key to toggle open and close

cc: @shadcn

const Tip = ({
  content,
  children,
  className
}: React.PropsWithChildren<{ content: string | React.ReactNode; className?: string }>) => {
  const [open, setOpen] = React.useState(false);

  return (
    <TooltipProvider delayDuration={0}>
      <Tooltip open={open}>
        <TooltipTrigger asChild>
          <button
            type="button"
            className={cn('cursor-pointer', className)}
            onClick={() => setOpen(!open)}
            onMouseEnter={() => setOpen(true)}
            onMouseLeave={() => setOpen(false)}
            onTouchStart={() => setOpen(!open)}
            onKeyDown={(e) => {
              e.preventDefault();
              e.key === 'Enter' && setOpen(!open);
            }}
          >
            {children}
          </button>
        </TooltipTrigger>
        <TooltipContent className={!content ? 'hidden' : ''}>
          <span className="inline-block">{content}</span>
        </TooltipContent>
      </Tooltip>
    </TooltipProvider>
  );
};

@cherkanovart
Copy link

Here is a tooltip that works on both mobile and desktop. We just handle all interactions ourselves. We get the added benefit of having this work with tabbing i.e. on a form and using the Enter key to toggle open and close

cc: @shadcn

const Tip = ({
  content,
  children,
  className
}: React.PropsWithChildren<{ content: string | React.ReactNode; className?: string }>) => {
  const [open, setOpen] = React.useState(false);

  return (
    <TooltipProvider delayDuration={0}>
      <Tooltip open={open}>
        <TooltipTrigger asChild>
          <button
            type="button"
            className={cn('cursor-pointer', className)}
            onClick={() => setOpen(!open)}
            onMouseEnter={() => setOpen(true)}
            onMouseLeave={() => setOpen(false)}
            onTouchStart={() => setOpen(!open)}
            onKeyDown={(e) => {
              e.preventDefault();
              e.key === 'Enter' && setOpen(!open);
            }}
          >
            {children}
          </button>
        </TooltipTrigger>
        <TooltipContent className={!content ? 'hidden' : ''}>
          <span className="inline-block">{content}</span>
        </TooltipContent>
      </Tooltip>
    </TooltipProvider>
  );
};

@devotox thx for the solution!
Maybe someone will find it useful.
IMO more intuitive behaviour:

...
  onClick={() => setOpen(true)}
  onMouseEnter={() => setOpen(true)}
  onMouseLeave={() => setOpen(false)}
  onTouchStart={() => setOpen(true)}
...

@devotox
Copy link

devotox commented Nov 13, 2024

Here is a tooltip that works on both mobile and desktop. We just handle all interactions ourselves. We get the added benefit of having this work with tabbing i.e. on a form and using the Enter key to toggle open and close

cc: @shadcn

const Tip = ({
  content,
  children,
  className
}: React.PropsWithChildren<{ content: string | React.ReactNode; className?: string }>) => {
  const [open, setOpen] = React.useState(false);

  return (
    <TooltipProvider delayDuration={0}>
      <Tooltip open={open}>
        <TooltipTrigger asChild>
          <button
            type="button"
            className={cn('cursor-pointer', className)}
            onClick={() => setOpen(!open)}
            onMouseEnter={() => setOpen(true)}
            onMouseLeave={() => setOpen(false)}
            onTouchStart={() => setOpen(!open)}
            onKeyDown={(e) => {
              e.preventDefault();
              e.key === 'Enter' && setOpen(!open);
            }}
          >
            {children}
          </button>
        </TooltipTrigger>
        <TooltipContent className={!content ? 'hidden' : ''}>
          <span className="inline-block">{content}</span>
        </TooltipContent>
      </Tooltip>
    </TooltipProvider>
  );
};

@devotox thx for the solution!
Maybe someone will find it useful.
IMO more intuitive behaviour:

...
  onClick={() => setOpen(true)}
  onMouseEnter={() => setOpen(true)}
  onMouseLeave={() => setOpen(false)}
  onTouchStart={() => setOpen(true)}
...

@cherkanovart for me the reason I did it the other way was I want it to be a toggle so that clicking or touching can open and close the tooltip

@kargnas
Copy link

kargnas commented Dec 13, 2024

I wish the tooltip worked on mobile devices as well. Since all Shadcn UI components and the Tailwind framework support various dimensions, including tablets, pc, and mobile devices, all features should be compatible across all devices. So I suggest reopening the issue @shadcn

@MijailVillegas
Copy link

MijailVillegas commented Jan 9, 2025

I wrote a simple solution that works fine for me so it can work both mouse and touchscreen

@shadcn @jozefdrabik

import * as TooltipPrimitive from "@radix-ui/react-tooltip"
import React from "react"

export const TooltipRoot = React.forwardRef<
  HTMLDivElement, 
  React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Root> & {
    useTouch?: boolean;
    useTap?: boolean;
  }
>(({ useTouch = false, useTap = false, children, ...props }, _ref) => {
  const [open, setOpen] = React.useState(false);

  const handleTouch = (event: React.TouchEvent | React.MouseEvent) => {
    event.persist();
    setOpen(true);
  };

  return (
    <TooltipPrimitive.Root
      open={open}
      onOpenChange={setOpen}
      {...props} 
    >
      {React.Children.map(children, (child) => {
        if (React.isValidElement(child) && useTouch) {
          return React.cloneElement(child as React.ReactElement<any>, {
            onTouchStart: handleTouch,
            onMouseDown: handleTouch,
          });
        }
        return child;
      })}
    </TooltipPrimitive.Root>
  );
});
TooltipRoot.displayName = TooltipPrimitive.Root.displayName;

usage:

<TooltipRoot useTouch={true}>
     <TooltipTrigger asChild>

 </TooltipRoot>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests