ui
ui copied to clipboard
Improvement: Tooltip and HoverCard Mobile Support
This is part of radix-ui
but I noticed that there is no mobile support for HoverCard or Tooltip components.
I have a web app where I use these for the desktop experience but a few users have said that it doesnt work on mobile, which is understandable given the library.
Just wanted to flag this as a possible future improvement. I'm thinking of implementing it myself, so I might open a PR to add tap support to Tooltips for mobile. Let me know if this is something we SHOULDNT pursue for any reason.
Might hold off on this: https://github.com/shadcn-ui/ui/issues/86
In case you "need a tooltip" use a popover instead, as they do in their documentation.
Yes, tooltips are designed for hover interaction while this interaction is not available on the mobile devices. However, I have noticed that some popular products use hybrid interactions based on the size on the screen.
- Desktop: Hover.
- Mobile: Click.
I'm confused on the situation in terms of triggering tooltips with mobile touch.
It seems like a really obvious thing that desktop hover and mobile click are 1:1, and I'm sure most people who start using shadcn and radix are going to assume this is how it works.
It seems like it's possible the authors disagree / ignore (e.g. #86), but I am not sure where that puts us. Does anyone have a solution for converting existing tooltips to work for mobile?
My app is basically unusable on mobile without tooltip support, so really desperate for a solution 🙏
But yeah @chukwumaokere I would totally use this change, it would be a lifesaver. Even if it didn't get merged I'd use the fork.
Here's a component following the logic described by @alamenai
'use client';
import { PropsWithChildren, createContext, useContext, useEffect, useState } from 'react';
import { Tooltip, TooltipTrigger, TooltipContent } from './tooltip';
import { Popover, PopoverTrigger, PopoverContent } from './popover';
import { TooltipContentProps, TooltipProps, TooltipTriggerProps } from '@radix-ui/react-tooltip';
import { PopoverContentProps, PopoverProps, PopoverTriggerProps } from '@radix-ui/react-popover';
const TouchContext = createContext<boolean | undefined>(undefined);
const useTouch = () => useContext(TouchContext);
export const TouchProvider = (props: PropsWithChildren) => {
const [isTouch, setTouch] = useState<boolean>();
useEffect(() => {
setTouch(window.matchMedia('(pointer: coarse)').matches);
}, []);
return <TouchContext.Provider value={isTouch} {...props} />;
};
export const HybridTooltip = (props: TooltipProps & PopoverProps) => {
const isTouch = useTouch();
return isTouch ? <Popover {...props} /> : <Tooltip {...props} />;
};
export const HybridTooltipTrigger = (props: TooltipTriggerProps & PopoverTriggerProps) => {
const isTouch = useTouch();
return isTouch ? <PopoverTrigger {...props} /> : <TooltipTrigger {...props} />;
};
export const HybridTooltipContent = (props: TooltipContentProps & PopoverContentProps) => {
const isTouch = useTouch();
return isTouch ? <PopoverContent {...props} /> : <TooltipContent {...props} />;
};
It mounts popover on touch devices and a tooltip by default.
thanks @luisdralves!
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 :thinking: so I reckon this issue can be closed.
@luisdralves can you please show an example of how to use the hybrid tooltip component?
Sure, it's very similar to the regular tooltip. Just wrap your layout with the touch provider so that the isTouch
state is calculated only once.
// Layout
import { TouchProvider } from '@/components/ui/hybrid-tooltip';
import './globals.css';
export default function RootLayout({ children }: React.PropsWithChildren) {
return (
<html lang='en'>
<body>
<TouchProvider>
<main>{children}</main>
</TouchProvider>
</body>
</html>
);
}
// Page
import { HybridTooltip, HybridTooltipContent, HybridTooltipTrigger } from '@/components/ui/hybrid-tooltip';
import { TooltipProvider } from '@/components/ui/tooltip';
//...
export default function Page() {
return (
<div className='flex items-center gap-2'>
<span>Tooltip example</span>
<TooltipProvider delayDuration={0}>
<HybridTooltip>
<HybridTooltipTrigger asChild>
<Button
type='button'
variant={'ghost'}
className='h-6 w-6 rounded-full p-1 text-muted-foreground'
>
<Info className='h-4 w-4' />
</Button>
</HybridTooltipTrigger>
<HybridTooltipContent>
<p>Content</p>
</HybridTooltipContent>
</HybridTooltip>
</TooltipProvider>
</div>
);
}
I propose a different alternative, take a look at this gist below, it uses @floating-ui/react
https://gist.github.com/oxuk85/34e6969d6ec3971f4561d69f26571bb4
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
I found the suggestion using popover does not look great on mobile devices.
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.