Idiomatic way to use Tooltips with buttons for touch vs hover devices?

3 replies
Last updated: Feb 16, 2021
Is there an idiomatic way to use Tooltips with buttons?
E.g. the following example is a bit a clunky on a touch device, since tapping the button also shows the tooltip (which just then sticks around) – which can be a bit awkward!
https://www.sanity.io/ui/arcade?mode=jsx&jsx=eJxVT0EOgjAQvPuKTS8ciR48GEoifsEPkLIhja[…]on=A+basic+example+of+using+the+Tooltip+primitive+in+Sanity+UI .
Ideally, I’d like to be able to recreate the behaviour of the existing publish button in Sanity (where you see a tooltip on hover with
fine pointers, but on touch devices / coarse pointers, tapping the button doesn’t reveal the tooltip)
AI Update

Great question! You're right that the default tooltip behavior can feel awkward on touch devices where tapping shows a tooltip that just sticks around.

While I can't find documented support for a disabled prop on the Sanity UI Tooltip component, there are a few approaches you can take to achieve touch-friendly tooltip behavior:

1. Use CSS pointer media queries to conditionally render the tooltip:

import {Button, Tooltip} from '@sanity/ui'
import {useEffect, useState} from 'react'

function TooltipButton() {
  const [showTooltip, setShowTooltip] = useState(true)
  
  useEffect(() => {
    // Check if device has a coarse pointer (touch)
    const isCoarsePointer = window.matchMedia('(pointer: coarse)').matches
    setShowTooltip(!isCoarsePointer)
  }, [])

  return showTooltip ? (
    <Tooltip content="Helpful information">
      <Button text="Click me" />
    </Tooltip>
  ) : (
    <Button text="Click me" />
  )
}

2. Wrap conditionally based on pointer capability:

const isCoarsePointer = window.matchMedia('(pointer: coarse)').matches
const button = <Button text="Click me" />

return isCoarsePointer ? button : (
  <Tooltip content="Helpful information">
    {button}
  </Tooltip>
)

3. Consider alternative patterns for touch devices:

Since tooltips are hover-based UI patterns that don't translate well to touch, you might want to:

  • Make button labels more descriptive so they don't need tooltips
  • Use a separate help icon that opens a popover on tap
  • Add contextual help text that's always visible on touch devices

The key insight is that @media (pointer: coarse) detects touch devices, while @media (pointer: fine) detects devices with precise pointing (like mice). This is more reliable than user-agent sniffing and aligns with how modern responsive design handles input modalities.

Without access to Sanity Studio's internal implementation, I can't confirm exactly how the publish button handles this, but the pointer media query approach is the standard web platform solution for this use case.

Show original thread
3 replies
If the tooltip is information that you want both mobile/touch devices and desktop users to have access to, but don’t want to force users on touch devices to open it before performing the action, I would recommend not using a button to trigger the tooltip. It’s not really expected or accessible behavior, if you think about a user’s thought process. If I’m using a mouse and not confident what a button is going to do, I might hover over it for a brief period to see if a title description pops up. On a touch device though, I’m not going to click on a button to get more information about what it does.So first things first, your button probably needs better copy if it’s not clear what it does. Second, if it’s not information a mobile user needs, then is it necessary at all? If it
is information a user on all devices should get, then the ideal pattern would be to have something like an info icon or “help” text that they can hover over to get the tooltip.
It's not baked in to
@sanity/ui
, but you could use the
disabled
property on the
Tooltip
to achieve it (see modified arcade here ). Will consider whether this should be the default behavior 🤔
(Fwiw, this is what the Studio does internally)

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?