Super Hover

A super tiny library that hit-tests hover every frame. Unlike native :hover, it keeps tracking whatever sits under your pointer while you scroll or when things move on screen.

001
Ambient
Moby
1993
002
Ambient
Moby
1993
003
Slave Ambient
The War On Drugs
2011
004
Death Ambient
Death Ambient
1995
005
Selected Ambient Works 85-92
Aphex Twin
2013
006
Ambient
Moby
2022
007
Ambient
Moby
008
Selected Ambient Works 85-92
Aphex Twin
2021
009
Ambient 1 (Music For Airports)
Brian Eno
1979
010
Ambient 4 (On Land)
Brian Eno
1982
011
Selected Ambient Works Volume II
Aphex Twin
2024
012
Ambient
Moby
1993
013
Ambient
Moby
014
Ambient 1 (Music For Airports)
Brian Eno
2018
015
Selected Ambient Works 85-92
Aphex Twin
1992
016
Ambient 1 (Music For Airports)
Brian Eno
1979
017
Ambient Dub Volume I
Divination
1993
018
Selected Ambient Works 85-92
Aphex Twin
2018
019
Ambient 1 (Music For Airports)
Brian Eno
1982
020
Ambient
Moby
1997
021
Selected Ambient Works Volume II
Aphex Twin
1994
022
Selected Ambient Works Volume II
Aphex Twin
2012
023
Ambient 2 (The Plateaux Of Mirror)
Harold Budd / Brian Eno
1980
024
Slave Ambient
The War On Drugs
2011
025
Ambient 4 (On Land)
Brian Eno
2018
026
Selected Ambient Works Volume II
Aphex Twin
1994
027
Ambient 3 (Day Of Radiance)
Laraaji Produced By Brian Eno
1980
028
Slave Ambient
The War On Drugs
2011
029
Ambient Boxed: A Guide By Instinct
Various
2001
030
Slave Ambient
The War On Drugs
2017
031
Hyper Ambient
Tokyo Offshore Project
1994
032
Ambient
Moby
033
Selected Ambient Works 85-92
Aphex Twin
034
Ambient 3 (Day Of Radiance)
Laraaji Produced By Brian Eno
1980
035
Ambient Systems
Various
1995
036
Selected Ambient Works Volume II
Aphex Twin
1994
037
Ambient
Voltage (13)
2017
038
Ambient 4 (On Land)
Brian Eno
2018
039
Ambient 4 (On Land)
Brian Eno
1982
040
Ambient 4: Isolationism
Various
1994
041
Hostile Ambient Takeover
Melvins
2021
042
Ambient 1 (Music For Airports)
Brian Eno
2018
043
Selected Ambient Works 85-92
Aphex Twin
1992
044
Selected Ambient Works 85-92
Aphex Twin
2006
045
Ambient
Moby
1993
046
Slave Ambient
The War On Drugs
047
Ambient Black Magic
Rainforest Spiritual Enslavement
2017
048
The Ambient Collection
Art Of Noise*
1990
049
Ambient Senses - The Vision
Various
1994
050
Ambient
Robert Piotrowicz / C. Spencer Yeh
2012
051
Slave Ambient
The War On Drugs
2011
052
Selected Ambient Works 85-92
Aphex Twin
053
Pop Ambient 2014
Various
2014
054
Ambient 2 (The Plateaux Of Mirror)
Harold Budd / Brian Eno
1980
055
Selected Ambient Works Volume II
Aphex Twin
1994
056
Selected Ambient Works 85-92
Aphex Twin
2013
057
Artcore - Ambient / Jungle
Various
1995
058
Selected Ambient Works Volume II
Aphex Twin
2017
059
Selected Ambient Works 85-92
Aphex Twin
060
Ambient Intermix
Various
1995
061
Ambient 1 (Music For Airports)
Brian Eno
2009
062
Selected Ambient Works 85-92
Aphex Twin
063
Ambient Systems: Limited Edition
Various
1999
064
Ambient 1
STRFKR*
2020
065
Ambient 1 (Music For Airports)
Brian Eno
1979
066
Ambient 1 (Music For Airports)
Brian Eno
1979
067
Selected Ambient Works 85-92
Aphex Twin
1992
068
Selected Ambient Works Volume II
Aphex Twin
069
Ambient Senses (The Vision)
Various
1994
070
Ambient
Moby
1996
071
Ambient
Erik Satie, Aldo Ciccolini
2003
072
Ambient 4 (On Land)
Brian Eno
1982
073
Ambient 1 (Music For Airports)
Brian Eno
1979
074
Pop Ambient 2002
Various
2001
075
Selected Ambient Works 85-92
Aphex Twin
076
Hotel : Ambient
Moby
2015
077
Ambient Blue
D Jay
1996
078
Selected Ambient Works 85-92
Aphex Twin
2002
079
Ambient 3 (Day Of Radiance)
Laraaji Produced By Brian Eno
2015
080
Ambient 1 (Music For Airports)
Brian Eno
1987
081
Ambient Intermix
Various
1995
082
Ambient Black Magic
Rainforest Spiritual Enslavement
2017
083
Ambient
Moby
1993
084
Pop Ambient 2015
Various
2014
085
Hostile Ambient Takeover
Melvins
2002
086
Ambient Light / Ambient Dark
Various
2024
087
Ambient 1 (Music For Airports)
Brian Eno
1979
088
Unlimited Ambient
Various
1997
089
Ambient Systems II
Various
1996
090
Hotel : Ambient
Moby
2015
091
Selected Ambient Works 85-92
Aphex Twin
092
Ambient 4 (On Land)
Brian Eno
1982
093
Ambient 1 (Music For Airports)
Brian Eno
1990
094
Selected Ambient Works 85-92
Aphex Twin
1992
095
Ambient 4 (On Land)
Brian Eno
2009
096
Selected Ambient Works Volume II
Aphex Twin
1994
097
Selected Ambient Works 85-92
Aphex Twin
098
Selected Ambient Works 85-92
Aphex Twin
2006
099
Ambient 1 (Music For Airports)
Brian Eno
1979
100
Selected Ambient Works
Aphex Twin
101
Selected Ambient Works
Aphex Twin
102
Ambient 1 (Music For Airports)
Brian Eno
1979
103
Artcore (Ambient/Jungle)
Various
1995
104
Ambient 4 (On Land)
Brian Eno
1982
105
Ambient Dub Volume 2. Earthjuice.
Various
1993
106
Pop Ambient 2002
Various
2001
107
Selected Ambient Works 85-92
Aphex Twin
108
Ambient 1 (Music For Airports)
Brian Eno
109
Pop Ambient 2003
Various
2002
110
4 Ambient Tales
Billie Ray Martin
1993
111
Ambient 4 / On Land
Brian Eno
1986
112
Ambient 1 (Music For Airports)
Brian Eno
2015
113
Ambient Systems 3
Various
1997
114
In Tyrannis / Ambient Grunge
Grungerman
1999
115
Selected Ambient Works 85-92
Aphex Twin
1992
116
Ambient 1 (Music For Airports)
Brian Eno
1979
117
Ambient / Ruin
Gravetemple
2013
118
Ambient 1 (Music For Airports)
Brian Eno
1982
119
Selected Ambient Works Volume II
Aphex Twin
1994
120
Pop Ambient 2005
Various
2004
121
Pop Ambient 2004
Various
2003
122
Pop Ambient 2001
Various
2001
123
Pop Ambient 2007
Various
2006
124
Ambient Meditations 2
Dr Alex Paterson*
1999
125
Ambient House - The Compilation
Various
1990
126
The Definitive Ambient Collection
Pete Namlook
1993
127
Ambient 1 (Music For Airports)
Brian Eno
1979
128
Ambient Auras: Diverse Dimensions In Ambient Dub
Various
1994
129
Ambient 1 (Music For Airports)
Brian Eno
130
Selected Ambient Works Volume II
Aphex Twin
1994
131
Ambient 1 (Music For Airports)
Brian Eno
2004
132
Ambient Meditations
Various
1998
133
Selected Ambient Works Volume II
Aphex Twin
2024
134
Instinct Ambient
Various
1994
135
Pop Ambient 2003
Various
2002
136
Ambient 1 (Music For Airports)
Brian Eno
1979
137
The Ambient Groove
Various
1994
138
Ambient
Moby
139
Ambient 4 (On Land)
Brian Eno
1982
140
Pop Ambient 2007
Various
2006
141
Selected Ambient Works 85-92
Aphex Twin
2002
142
Ambient
Moby
143
Pop Ambient 2008
Various
2007
144
Selected Ambient Works Volume II
Aphex Twin
2024
145
Pop Ambient 2006
Various
2005
146
Ambient Hawaiʻi
Ambient Hawai'i
1997
147
Ambient 1 (Music For Airports)
Brian Eno
1979
148
Ambient 4 (On Land)
Brian Eno
1982
149
Ambient 1 (Music For Airports)
Brian Eno
1990
150
The Ambient Cookbook
Various
1995
151
Ambient 1 (Music For Airports)
Brian Eno
1987
152
Selected Ambient Works 85-92
Aphex Twin
1992
153
Ambient 4 (On Land)
Brian Eno
2004
154
Pop Ambient 2004
Various
2003
155
Ambient 3 (Day Of Radiance)
Laraaji Produced By Brian Eno
1980
156
The Triad Ambient Versions
Pantha Du Prince
2017
157
Ambient 1 (Music For Airports)
Brian Eno
158
Selected Ambient Works 85-92
Aphex Twin
1994
159
Pop Ambient 2005
Various
2004
160
Ambient
Slowdive
1993
161
Selected Ambient Works Volume II
Aphex Twin
1994
162
環境音楽 = Kankyō Ongaku (Japanese Ambient, Environmental & New Age Music 1980 - 1990)
Various
2019
163
Ambient-Compilation 4
Various
1993
164
Ambient 4 (On Land)
Brian Eno
1987
165
Ambient 4 (On Land)
Brian Eno
1982
166
Ambient
Moby
1993
167
Ambient Dub Volume 3 (Aqua)
Various
1993
168
Pop Ambient 2006
Various
2005
169
Selected Ambient Works 85-92
Aphex Twin
2011
170
Ambient 1 (Music For Airports)
Brian Eno
1987
171
Ambient 2 (The Plateaux Of Mirror)
Harold Budd / Brian Eno
1982
172
LP2 Ambient Dance
Earth Trax
2020
173
Ambient 3 (Day Of Radiance)
Laraaji Produced By Brian Eno
1982
174
Ambient 3 (Day Of Radiance)
Laraaji Produced By Brian Eno
1987
175
Pop Ambient 2008
Various
2007
176
Pop Ambient 2010
Various
2010
177
Ambient 2 (The Plateaux Of Mirror)
Harold Budd / Brian Eno
1980
178
Ambient
Moby
179
Ambient Amazon
Various
1995
180
Hostile Ambient Takeover
Melvins
2002
181
Ambient 1 (Music For Airports)
Brian Eno
182
Selected Ambient Works 85-92
Aphex Twin
1999
183
Ambient
Moby
184
Ambient 4 (On Land)
Brian Eno
1982
185
Selected Ambient Works 85-92
Aphex Twin
186
Pop Ambient 2012
Various
2012
187
Selected Ambient Works 85-92
Aphex Twin
2000
188
Ambient 1 (Music For Airports)
Brian Eno
1979
189
Pop Ambient 2011
Various
2011
190
Selected Ambient Works Volume II
Aphex Twin
1994
191
Ambient 4 (On Land)
Brian Eno
1982
192
Ambient Theology
Ambient Theology
1995
193
Ambient Soho
Various
2000
194
Ambient 3 (Day Of Radiance)
Laraaji
1980
195
Ambient Amazon
Various
1995
196
Selected Ambient Works 85-92
Aphex Twin
197
Selected Ambient Works Volume II
Aphex Twin
1994
198
Freezone 1 : The Phenomenology Of Ambient
Various
1994
199
Pop Ambient 2009
Various
2009
200
Pop Ambient 2014
Various
2014
Scrollable list comparing native vs Super Hover with hover-triggered styling

Why use this?

Well, you probably shouldn't. While scrolling, browsers mostly skip updating :hover to prioritize other important rendering work, which in most cases is the desired behavior. But Super Hover recomputes a hover-like hit every frame, which opens up the possibility of some fun creative effects and interactions.

Installation

1pnpm add super-hover

Usage

Wrap the area you care about, then mark the things that should act hoverable.

The active element gets data-super-hover-active, which is usually enough if you only want styling.

Basic usage

1import { useSuperHoverRef } from "super-hover/react";
2
3export function Example() {
4 const rootRef = useSuperHoverRef();
5 const items = ["Inbox", "Projects", "Settings"];
6
7 return (
8 <ul ref={rootRef} className="space-y-1">
9 {items.map((item) => (
10 <li
11 key={item}
12 data-super-hover
13 className="rounded-md px-3 py-2 data-[super-hover-active]:bg-neutral-100"
14 >
15 {item}
16 </li>
17 ))}
18 </ul>
19 );
20}

Events

If styling is not enough, you can run code when the active element changes. Super Hover dispatches three custom events:

In React, useSuperHoverRef exposes these as onEnter, onLeave, and onMove.

Images on the right are synced when the enter event fires.

Event handlers

1import { useSuperHoverRef } from "super-hover/react";
2
3export function Example() {
4 const rootRef = useSuperHoverRef({
5 onEnter(event) {
6 console.log("entered", event.detail.current);
7 },
8 onLeave(event) {
9 console.log("left", event.detail.previous);
10 },
11 });
12
13 const items = ["Inbox", "Projects", "Settings"];
14
15 return (
16 <ul ref={rootRef} className="space-y-1">
17 {items.map((item) => (
18 <li
19 key={item}
20 data-super-hover
21 className="rounded-md px-3 py-2 data-[super-hover-active]:bg-neutral-100"
22 >
23 {item}
24 </li>
25 ))}
26 </ul>
27 );
28}

onMove is off by default. If you need pointer coordinates for things like tooltips or previews, pass onMove and read event.detail.x / event.detail.y.

Event detail

The events are CustomEvents, so the useful data lives on event.detail.

For superhoverenter and superhoverleave, detail has:

For superhovermove, detail has:

previous and current are DOM elements. If you need a value from your item, read it from the element with dataset, id, or whatever you rendered there.

Reading event detail

1import { useSuperHoverRef } from "super-hover/react";
2
3export function Example() {
4 const rootRef = useSuperHoverRef({
5 onEnter(event) {
6 const { x, y, previous, current } = event.detail;
7 console.log(x, y);
8 console.log(previous?.id);
9 console.log(current?.dataset.superHoverIndex);
10 },
11 });
12
13 return (
14 <ul ref={rootRef}>
15 <li id="inbox" data-super-hover>Inbox</li>
16 <li id="projects" data-super-hover>Projects</li>
17 <li id="settings" data-super-hover>Settings</li>
18 </ul>
19 );
20}

How it works

The library is very simple and short, so please read the source code (or ask your agent) for the full details.

In short, Super Hover keeps track of the last pointer and when the pointer moves, the page scrolls, or the viewport changes, it schedules a hit-test with requestAnimationFrame. Multiple updates in the same frame are coalesced, so they only produce one hit-test.

On that frame, Super Hover calls elementFromPoint(x, y), finds the closest element matching [data-super-hover], and updates the active element.

If the active element changes, Super Hover removes data-super-hover-active from the old element, adds it to the new one, and dispatches the custom events.

What about content-visibility?

Optimizing heavy content with content-visibility: auto can also make native hover feel more responsive. It lets the browser skip rendering for content until it is needed, which can leave enough room for :hover to update more often while scrolling.

That said, what the browser schedules, and how it prioritizes those updates is a bit of a black box to me, and the result does not seem fully deterministic. Super Hover, on the other hand, recomputes the active element from the last pointer position every frame. Of course, if the page is overloaded enough to drop frames, Super Hover can drop frames too.

If you have better insight into how browsers prioritize this, please . I would genuinely love to hear it.

Accessibility

Super Hover can make the interface change quickly during scroll or animated layout changes, which can be jarring for people who are sensitive to motion.

If you use it in production, please respect reduced-motion preferences. Either disable it when it makes sense,or provide an equivalent opt-out.

Respect reduced motion

1import { useEffect, useState } from "react";
2import { useSuperHoverRef } from "super-hover/react";
3import { useReducedMotion } from "motion/react"
4
5export function Example() {
6 const prefersReducedMotion = useReducedMotion();
7
8 const rootRef = useSuperHoverRef({
9 enabled: !prefersReducedMotion,
10 });
11
12 return <ul ref={rootRef}>{/* ... */}</ul>;
13}

API

SuperHoverOptions

createSuperHover registers listeners for pointer moves, scroll, and resize, then hit-tests on scheduled animation frames. Pass these fields as options. It returns a controller with pause(), resume(), refresh(), and destroy().

On each scheduled hit-test, the library calls elementFromPoint, walks ancestors with closest(selector) to pick the nearest matched element, and—when root is set—verifies that it lies inside root. selector decides which nodes may activate; root only limits where hits count—it does not automatically target every descendant.

enabled:boolean

Default: true

Starts the controller running. When false, it starts paused and waits for resume().

pointerTypes:("mouse" | "pen" | "touch")[]

Default: ["mouse", "pen"]

Pointer types allowed to update the tracked pointer position. Touch is off by default so finger scrolling does not create hover state.

root:Document, Element, or omit

Default: whole document

Optional boundary: the matched element must lie inside this subtree; omit for the whole document. You can pass an iframe Document or an element inside a same-origin iframe. Does not make every descendant node a target; that is controlled by selector instead.

selector:string

Default: [data-super-hover]

CSS selector passed to element.closest from the hit-tested node; defines which elements may activate (default [data-super-hover]). Independent of root, which only scopes where hits count.

activeAttribute:string

Default: data-super-hover-active

Attribute toggled on the active matched element (empty string while active, removed otherwise). Use it for styling, e.g. data-[super-hover-active]:….

enterEventType:string

Default: superhoverenter

CustomEvent type dispatched on the matched element when it becomes active (bubbles: true).

leaveEventType:string

Default: superhoverleave

CustomEvent type dispatched on the matched element when it stops being active. event.detail includes x, y, previous, and current.

moveEventType:string or false

Default: superhovermove

CustomEvent type dispatched on each scheduled hit-test while an element is active. Set to false to disable move events.

UseSuperHoverOptions

UseSuperHoverOptions for useSuperHover(root, options) and useSuperHoverRef(options) from super-hover/react. Pass the mounted root as the first argument to useSuperHover, or use the callback ref returned from useSuperHoverRef.

enabled:boolean

Default: true

When false, the React helper does not mount Super Hover on the root.

pointerTypes:("mouse" | "pen" | "touch")[]

Default: ["mouse", "pen"]

Pointer types allowed to update the tracked pointer position. Touch is off by default.

selector:string

Default: [data-super-hover]

CSS selector passed to element.closest from the hit-tested node; defines which elements may activate (default [data-super-hover]). Independent of root, which only scopes where hits count.

activeAttribute:string

Default: data-super-hover-active

Attribute toggled on the active matched element (empty string while active, removed otherwise). Use it for styling, e.g. data-[super-hover-active]:….

enterEventType:string

Default: superhoverenter

CustomEvent type dispatched on the matched element when it becomes active (bubbles: true).

leaveEventType:string

Default: superhoverleave

CustomEvent type dispatched on the matched element when it stops being active.

moveEventType:string or false

Default: auto

Custom move event name, or false to disable move events. If neither onMove nor moveEventType is passed, the React helper disables move events for you.

onEnter:(event: SuperHoverEnterEvent) => void

Default: no-op

Runs when an enter event bubbles within root. event.detail includes x, y, previous, and current.

onLeave:(event: SuperHoverLeaveEvent) => void

Default: no-op

Runs when a leave event bubbles within root. event.detail includes x, y, previous, and current.

onMove:(event: SuperHoverMoveEvent) => void

Default: off

Runs on move events while an element is active. The helper only listens for move events when onMove is passed.

SuperHoverEventDetail

Used by superhoverenter, superhoverleave, onEnter, and onLeave.

x:number

Last pointer x position in viewport coordinates.

y:number

Last pointer y position in viewport coordinates.

previous:Element | null

Element that was active before this change, or null.

current:Element | null

Element that is active after this change, or null.

SuperHoverMoveEventDetail

Used by superhovermove and onMove.

x:number

Last pointer x position in viewport coordinates.

y:number

Last pointer y position in viewport coordinates.

current:Element

Currently active element.