Your Hover States Are Invisible to 60% of Your Users

Cover Image for Your Hover States Are Invisible to 60% of Your Users

Your component library has 47 hover states. Your design documentation describes hover behaviors for menus, cards, buttons, tooltips, table rows, and data visualizations. Your design review process checks that hover states are visually polished.

More than 60% of your users have never seen any of them.

Mobile web traffic has been majority-mobile globally since 2016. As of 2025, Statcounter puts mobile at consistently above 60% of all web traffic. Touch devices — phones, tablets — do not have hover events. When a user touches a screen, the browser fires a click event directly, sometimes preceded by a synthetic mouseover, but the hover state interaction model doesn't exist. There's nothing to hover with.

This is not breaking news. Every designer knows touch devices exist. The problem is that knowing it abstractly and actually auditing for hover-only patterns are different things. Most teams do the former and skip the latter.

What Hover Hides

The deeper issue is that hover states often carry real information — information that only some users can see.

Hover-reveal menus. Desktop navigation patterns often use hover to reveal dropdown or flyout menus. The user positions their cursor near a nav item, the submenu appears. On touch, this doesn't work. Touch navigation patterns have to be click/tap based. Teams building for desktop-first often implement hover menus and add a tap behavior as an afterthought — except the tap behavior opens the top-level link, not the submenu. Touch users can't access the submenu at all.

Tooltips. Most tooltips are hover-triggered. They contain context, definitions, warnings, or help text that the UI relies on to communicate meaning. On touch, that information is inaccessible unless you've added an explicit tap alternative. A lot of teams have not.

Hover-to-reveal actions. Table rows, cards, and list items frequently use hover to reveal action buttons — edit, delete, share. The user hovers, the actions appear. On touch, the hover never triggers. The actions don't appear. The user has to discover another path to the action (a context menu, a separate detail view, a long-press if you've implemented it) or concludes the action doesn't exist.

Hover-state-only feedback. This is subtle but common: interactive elements that use hover state as their only visual indicator that they're interactive. A link that underlines on hover. A card that lifts on hover. A button that changes color on hover. These patterns teach desktop users "this is clickable." Touch users see a static element and sometimes guess correctly.

None of these are edge cases. They're standard UI patterns that appear in design systems from companies that know better.

WCAG and the :focus Problem

WCAG 2.1 includes Success Criterion 1.4.13: Content on Hover or Focus, which addresses the accessibility dimension of hover-triggered content. The criterion requires that hover-triggered content be dismissable, hoverable (you can move your cursor over it), and persistent (it doesn't disappear without user action).

This addresses one specific failure mode — content disappearing before users can interact with it — but not the fundamental problem. You can perfectly comply with 1.4.13 while still creating a UI where touch users can't access the content at all.

The more useful audit target is your :hover CSS selectors. Any rule that applies only to :hover without a corresponding :focus, :focus-visible, or :focus-within rule is a touch accessibility gap. Keyboard users also can't hover, so this gap covers keyboard navigation too.

The audit is simple in principle: search your CSS for :hover and check each instance for a focus equivalent. In practice, it produces a long list. Existing codebases typically have dozens to hundreds of hover-only rules. Each one represents either a deliberate choice to hide something from touch and keyboard users, or an oversight.

The Design System Gap

Design systems often introduce these problems at scale. A component is built with hover behaviors on desktop, the hover behavior is documented, and teams implement it across the product. The hover state becomes a pattern. Nobody asks "what happens on touch?" because the component specification doesn't address it, and the designer who wrote the spec was working on a laptop.

When the design system codifies the hover pattern, it codifies the gap. Fixing it later requires either updating the specification for all components or living with inconsistency as individual teams patch their own implementations. Neither is easy at scale.

The teams doing this well build touch interaction into component specifications from the start. For every interactive element, the specification includes both pointer (hover/click) and touch (tap) behaviors. If a behavior depends on hover, the spec addresses what touch users get instead — or whether the behavior should exist at all.

The Better Question

Before adding hover behavior, the better question is: why does this information require hovering to reveal?

Hover behaviors often exist to manage information density — hiding content that would clutter the interface if always visible. That's a legitimate goal. But the solution to information density isn't to hide content behind an interaction that half your users can't trigger. It's to find a way to present the content that works at all sizes and on all input types.

Some patterns that work across input types:

  • Persistent visible labels instead of hover-reveal labels on icon buttons
  • Expandable sections instead of hover menus
  • Inline help text or linked documentation instead of tooltips
  • Contextual menus behind a tap-target (a ••• button, a disclosure widget) instead of row-hover actions
  • Clear visual affordances (underline, border, clear button treatment) instead of hover-change-only interactivity signals

None of these are harder to implement than their hover equivalents. They're different. The friction is usually that the desktop version was built first and touch was retrofitted.

An Audit That Takes an Hour

Run this on your product next time you have an hour:

Open your application on a phone. Don't use Chrome DevTools device emulation — use a real phone. Try to complete five core user flows. Note every place where you're not sure where to tap, every action that's harder to find than you expected, and every point where the desktop version would show you something that the mobile version doesn't.

You will find at least a few hover gaps. Most interfaces have more than a few. The results from this kind of audit are rarely neutral — they usually produce a list of specific, actionable gaps that you didn't know existed because nobody on the team runs your product on a phone.

The best hover state is the one that doesn't need to exist because the information it was revealing is visible by default.

Hover is a capability. The web is not only accessed by people who have it.


Photo by Towfiqu barbhuiya via Pexels.