utility (aa-hover-trigger)
aa-hover-trigger is a marker attribute placed on a wrapper. Any descendant element with aa-hover listens to the wrapper's mouseenter/leave, not its own. This lets you build composite buttons where the background, icon, and text each carry their own single aa-hover effect (no flag collisions) but all fire from one shared hover region.
If no aa-hover-trigger exists on the page, every aa-hover element is its own trigger.
How it works
Section titled “How it works”At init the hover feature scans for [aa-hover-trigger] once, then maps every descendant [aa-hover] to its owning trigger. Top-down so the mental model is clear: the trigger wraps these children. Nested triggers correctly hand ownership to the innermost (document-order writes win).
Each effect still runs against its own host element — only the event source changes. So a <svg aa-hover="icon-right"> inside the trigger still wraps its icon in a clip box on the SVG; a <span aa-hover="text"> still splits the span's text into chars. The trigger only decides when to fire.
Authoring rules
Section titled “Authoring rules”- Put
aa-hover-triggeron the wrapper that should drive the hover. - Give each child a single
aa-hovervalue with its own flags (icon-right reverse,curve vertical,text reverse, …). - Set
aa-duration/aa-delay/aa-easeon each child individually. They share the event, not the timing — that's intentional so you can have the icon snap in faster than the curve sweeps. aa-coloris per-effect — set it on each child you want coloured.
Live demo — curve + text reverse + icon-right on one button
Section titled “Live demo — curve + text reverse + icon-right on one button”The wrapper carries the curve (four-direction by default — entry edge follows the cursor). The label chars lift and stay up while hovered (text reverse). The arrow slides off to the right; a clone slides in from the left and snaps back on leave (icon-right reverse). All three fire from the wrapper's mouseenter, even when the cursor sits inside the label or icon-box. aa-color on the icon recolours the slide-in clone so it stays visible against the black curve.
<a class="cmp-btn" href="#" aa-hover-trigger aa-hover="curve" aa-color="#131313" aa-duration="0.6"> <span class="cmp-btn-label" aa-hover="text reverse" aa-color="#ffffff" aa-duration="0.5"> Click me </span> <span class="cmp-btn-icon" aa-hover="icon-right reverse" aa-color="#ffffff" aa-duration="0.5"> <svg viewBox="0 0 24 24" aria-hidden="true"> <path d="M5 12h14M13 6l6 6-6 6" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round" /> </svg> </span></a>Live demo — underline-in + text reverse nested
Section titled “Live demo — underline-in + text reverse nested”Two effects on the same word. The outer span owns the underline bar (underline-in); the inner span owns the char lift (text reverse). Both fire from the <a>'s mouseenter via the trigger map, so hovering anywhere on the link drives both at once.
A small padding-bottom on the underline-in span keeps the bar from overlapping the descenders of the incoming text-shadow as the chars lift up — without it, the bar would sit on the same baseline the shadow's g/y-style descenders land on.
<a class="cmp-link" href="#" aa-hover-trigger> <span aa-hover="underline-in" aa-duration="0.5" style="padding-bottom: 0.15em"> <span aa-hover="text reverse" aa-duration="0.5">Click me</span> </span></a>