Develop

Privacy-preserving hover design for 2D apps

Updated: Sep 4, 2026
The Look and Pinch system renders hover effects on behalf of your app. Because your app does not receive hover events, you need to design your selection affordances so the transition from system hover to app selection appears seamless.
For an overview of how the privacy-preserving interaction model works, see Look and Pinch for 2D apps.

How the system hover effect looks

The system hover effect is a semi-transparent highlight overlay that the system renders on top of interactable elements when the user’s gaze rests on them. The overlay follows the shape of the element (rounded rectangle, circle, or custom path) as reported by the element’s outline provider or shape modifier. When the user looks away, the hover effect fades out. When the user pinches to select, the hover effect fades out and the system sends a touch event to your app.
The hover effect lightens the element’s appearance. Both light and dark themed apps should expect the hovered element to appear brighter than its resting state. For color theming and contrast guidance, see Eyes Best Practices.

Match selected element visuals to hover shape

When the user performs a select gesture (pinching their fingers), the system fades out the hover effect and sends a touch event to your app. At that point, your app’s selection affordance (pressed state, focus ring, or other visual feedback) fades in. If the shapes and styles of the system hover and app selection differ significantly, the crossfade appears jarring.
By default, the system infers the element’s shape and displays a matching hover effect. If the inferred shape does not match your element’s visual appearance, you can provide a custom shape explicitly. See Provide element shape and bounds for implementation details.
To achieve a seamless transition:
  • Design your pressed/selected state to match the shape and bounds of the element’s outline.
  • If your button has rounded corners, verify the system hover effect also uses rounded corners by setting the appropriate outline provider or shape modifier.

Highlight logically grouped components

Hover effects should highlight the entire component of logically grouped content, not individual sub-elements. For example, a card component that contains an image, a title, and a description should highlight as a single hover target covering the entire card.
To achieve this:
  • Mark the entire parent component (such as the card container) as the interactive element, not its individual children.
  • Provide a custom hover shape that encompasses the full grouped content if needed.
See Mark elements as interactable for how to configure which elements are treated as interactive targets, and Provide element shape and bounds for specifying a custom hover shape.

Avoid hover effects on non-interactable content

Hover effects should only appear on elements that the user can interact with. If a non-interactable element (such as a static text block or decorative image) is incorrectly marked as interactable, the system will target it and render a hover highlight, confusing users.
To prevent this:
  • Verify that non-interactable elements do not have click listeners or interactable modifiers attached.
  • For Android Views, check that decorative elements do not return true for hasOnClickListeners() or isClickable().
  • For Jetpack Compose, verify that non-interactable composables do not include Modifier.clickable.
See Mark elements as interactable for the full list of conditions the system uses to determine interactability.

Suppress hover effects on media views

When your app displays media content such as videos or still images, the media itself is often clickable (for example, clicking a video to bring up playback controls). Because the system applies a hover effect to interactable elements, this results in a persistent hover overlay appearing over the content while the user is looking at it.
This is undesirable for media viewing. Users should be able to watch a video or view an image without a hover effect obscuring the content.
To reduce this issue, consider whether the media element needs to be marked as interactable at all times. If playback controls appear on tap, the media container can be marked as non-interactable during playback and re-marked as interactable when controls are needed.
With the Gaze SDK for Android Views, mark the media view as not important for interaction during playback.
Example: Toggling a media view’s interactable state in Android Views:
// During playback, suppress hover by removing click listener
mediaView.setOnClickListener(null);

// When controls are needed, restore interactability
mediaView.setOnClickListener(v -> showPlaybackControls());
See Mark elements as interactable for details on controlling interactable state across all frameworks.

Troubleshooting

Hover effect shape does not match selection state

Symptom: When the user selects an element, the transition between the system hover highlight and your app’s pressed/focused state appears jarring or misaligned.
Solution: Verify that your element’s outline provider (Android Views) or clip modifier (Jetpack Compose) defines a shape that matches your selection affordance. If the element uses rounded corners, set the same corner radius on the outline. See Provide element shape and bounds.

Non-interactable element shows a hover effect

Symptom: A decorative element, static text, or background image receives a hover highlight when the user looks at it.
Solution: Check that the element does not have a click listener or Modifier.clickable set. Remove any interactable attributes from elements that should not respond to gaze input. See Mark elements as interactable.

Individual sub-elements highlight instead of the parent card

Symptom: When the user looks at a card component, individual child elements (image, title, description) each show separate hover highlights instead of one highlight covering the entire card.
Solution: Move the click listener to the parent card container and remove click listeners from child elements. The system targets the highest-level interactable element in the hierarchy. If the parent is the only interactable element, the hover effect covers the entire card.