All articles
Design & UXAugust 27, 2026 6 min read

Hover Is Not an Interaction: Designing for Touch-First Without Breaking the Desktop

Hover states quietly hide critical UI from most of your users. Here's how to design interactions that work on touch, keyboard, and mouse without shipping three different UIs.

Every few months we audit a client's product and find the same pattern: critical actions — delete, edit, options, secondary metadata — tucked behind :hover. On desktop it looks clean. On a phone, tablet, or with a keyboard, half the interface is invisible or requires a scavenger hunt. Hover is not an interaction. It's a hint, at best, and it's time we designed like we believe that.

Why Hover Broke

Hover made sense when the web was mouse-only. A pointer had a clear, persistent position, and revealing controls on hover kept dense interfaces breathable. That world is gone. Somewhere between 55% and 70% of traffic on most consumer products we ship is touch, and even on desktop a growing share of users navigate primarily with keyboards, trackpads with gesture shortcuts, or assistive tech that doesn't emit a hover event at all.

The symptoms are predictable:

  • Row actions (edit, archive, more) invisible on mobile until the user long-presses something they weren't sure was tappable.
  • Tooltips carrying the only label for an icon button, unreachable on touch.
  • Dropdown menus that open on hover and close the moment a touch user's finger leaves the trigger.
  • Card overlays with CTAs that require hover to appear, which on iOS require a phantom first-tap to reveal and a second to activate.

None of this is a mobile bug. It's a design assumption bug.

The Mental Model Shift: Hover Is a Progressive Enhancement

The rule we use on every project now: any information or action that is required to complete a task must be reachable without hover. Hover can add polish — a subtle elevation, a preview, a shortcut hint — but it can never be the primary channel.

Think of it the way you think of JavaScript in a progressive enhancement stack. The core experience works without it. Hover is icing.

That means for every hover state in your design system, you owe an answer to three questions:

  1. What does a touch user see and do?
  2. What does a keyboard user see and do?
  3. What does a screen reader announce?

If the answer to any of these is "nothing" or "they figure it out," the pattern isn't done.

Detecting Input, Not Screen Size

The most common mistake is gating hover behavior on viewport width. A 13-inch iPad Pro in landscape is wider than plenty of laptops, and plenty of laptops now have touch screens. Use the pointer media queries instead — they've been well-supported for years and they ask the right question.

/* Fine-grained pointer (mouse, trackpad) */
@media (hover: hover) and (pointer: fine) {
  .row-actions {
    opacity: 0;
    transition: opacity 150ms ease;
  }
  .row:hover .row-actions,
  .row:focus-within .row-actions {
    opacity: 1;
  }
}

/* Coarse pointer (touch) or no hover capability */
@media (hover: none), (pointer: coarse) {
  .row-actions {
    opacity: 1;
  }
}

A few things worth noticing in that snippet:

  • focus-within sits alongside :hover so keyboard users get the same reveal. This is the single cheapest accessibility win in most codebases.
  • The touch branch doesn't try to simulate hover. It just shows the controls. Simpler, less fragile, and honest about what the device can do.
  • We're testing hover and pointer together, because devices with both (a Surface, an iPad with a trackpad) should get the richer behaviour.

Don't Forget the Hybrid Case

Hybrid devices are a real category now, and the pointer queries evaluate against the primary input. A user on a Surface with a mouse plugged in gets hover: hover, then unplugs the mouse mid-session and gets nothing until the queries re-evaluate. Design so that both branches are usable, not so that one is broken.

Pattern Rewrites: Four Common Offenders

1. Row Action Menus

The worst offender in every SaaS product we audit. Table rows with edit/delete/duplicate icons that appear on hover.

Fix: On touch, show a single overflow (⋯) button that opens a menu. On pointer devices, either show the icons persistently at low visual weight, or reveal them on hover and on keyboard focus. Never let the hover version be the only version.

2. Icon-Only Buttons With Tooltip Labels

A gear icon with a hover tooltip that says "Settings" is unlabelled UI on mobile.

Fix: Always ship a real aria-label. On touch, consider showing the label as text below the icon at small sizes, or accept the icon-only pattern only when the meaning is genuinely universal (search, close, back). If you need a tooltip for context, that context is nice-to-have, not the label itself.

3. Hover-to-Open Dropdowns

Mega-menus that open on hover feel snappy on desktop and are unusable on touch. iOS will fire a mouseenter on first tap and swallow the second, or open the menu and immediately close it.

Fix: Trigger dropdowns on click/tap universally. If you love hover on desktop, add a small delay and use focus-within for keyboard parity, but the click behaviour must work everywhere.

// Simplified — trigger on click, hover is bonus
function MenuTrigger({ children, menu }) {
  const [open, setOpen] = useState(false);

  return (
    <div
      className="menu-wrapper"
      onMouseLeave={() => setOpen(false)}
    >
      <button
        aria-expanded={open}
        aria-haspopup="menu"
        onClick={() => setOpen(o => !o)}
      >
        {children}
      </button>
      {open && <div role="menu">{menu}</div>}
    </div>
  );
}

Notice there's no onMouseEnter opening the menu. You can add it behind a (hover: hover) check if you want, but the click path is the source of truth.

4. Card Overlays

Product grids where the CTA ("Quick view", "Add to cart") only appears when the card is hovered. On mobile this is either invisible or requires the phantom-tap dance.

Fix: Show the CTA persistently on touch. On desktop, if you must animate it in on hover, make sure tapping anywhere on the card also triggers the primary action, and give the card a clear affordance that it's interactive at rest.

The Focus-Within Trick Deserves Its Own Section

If you take one thing from this article: audit every :hover in your CSS and add :focus-within next to it where it makes sense.

.card:hover .card__actions,
.card:focus-within .card__actions {
  opacity: 1;
  transform: translateY(0);
}

This single change makes hover-revealed UI reachable by keyboard. It costs nothing, breaks nothing, and quietly fixes a large class of accessibility complaints. We've shipped this as a linting rule on a couple of projects — any :hover selector that reveals content must have a matching :focus-within or :focus-visible selector, or it fails review.

Motion and Hover: A Note on Restraint

Hover animations are where designers still get to have fun, and that's fine. Keep the motion ratio short — 120–200ms for state changes, tighter easing than you think — and always respect prefers-reduced-motion. If your hover reveal has a 400ms elastic bounce, you're not designing an interaction, you're designing a demo reel.

@media (prefers-reduced-motion: reduce) {
  .card__actions {
    transition: none;
  }
}

Related reading if you want to go deeper on the engineering side of design tokens and cross-device patterns, we've written more on our blog and offer this kind of audit as part of our design and frontend services.

What We'd Do Monday Morning

If you inherit a codebase full of hover-dependent UI, don't try to fix it all at once. Start here:

  1. Grep for :hover in your CSS. For each match, ask: does this reveal content, or does it just restyle existing content? The reveals are your priority list.
  2. Add :focus-within next to every reveal. Ship it. That's a keyboard accessibility win in an afternoon.
  3. Wrap reveal styles in @media (hover: hover). Now touch users see the controls by default.
  4. Audit your icon-only buttons. Every one needs a real aria-label, not just a tooltip.
  5. Kill hover-to-open menus. Convert them to click/tap with hover as a bonus behind a media query.

None of this requires a redesign. It requires treating hover like the enhancement it always was, and giving the other 60% of your users a UI that shows up when they do.

#UX#Accessibility#Frontend#Design Systems

Want a team like ours?

72Technologies builds production software for the kind of teams who actually read this blog.

Start a project