underline
aa-hover="underline-in" and aa-hover="underline" add an animated underline bar at the bottom of the host. The library appends a single <span aa-hover-underline> and animates its scaleX — no HTML changes required. Rapid flicks stay directionally clean via an asymmetric interrupt model: a leave during IN is queued (the full IN runs first, then OUT), and an enter during OUT fast-forwards the in-flight shrink to ~100 ms before growing back in from the left — so OUT always retracts rightward and IN always grows leftward, even on quick reversals.
Touch-only devices skip the effect via (hover: hover) so iOS / Android don't fire stuck animations on tap.
Variants
Section titled “Variants”| Variant | Default state | On hover |
|---|---|---|
underline-in | No underline | Bar grows left → right; on leave, shrinks right-ward back to 0. |
underline | Underline always shown | Bar collapses toward the right edge, then re-grows from the left. Two phases. |
Attributes
Section titled “Attributes”| Attribute | Default | Notes |
|---|---|---|
aa-hover | (required) | underline-in or underline |
aa-color | currentColor | Bar background-color |
aa-duration | (init) | Seconds. For underline, this is the total sweep time (split into two halves). |
aa-delay | 0 | Seconds before the enter animation starts. |
aa-ease | (init) | Any GSAP ease — falls back to init({ ease }) (default power4.out). |
CSS variables
Section titled “CSS variables”The injected bar's layout (position, width, height, transform-origin, the offset math) all live in alrdy-animate.css — that import is required for the underline head, see the Next.js install guide or the Webflow install guide. Without it the bar renders as a static unstyled span.
Set on the host, an ancestor, or :root. In Webflow, paste into a Custom Code embed <style> block — the Designer's Style panel can't author CSS custom properties.
| Variable | Default | Notes |
|---|---|---|
--aa-hover-underline-thickness | 0.0625em | Bar height. |
--aa-hover-underline-offset | 0 | Positive pushes the bar further below the text; negative pulls it up. Auto-bumped to 0.05em for bars inside a <p> so inline links clear deep descenders. |
Touch devices
Section titled “Touch devices”The hover feature is skipped entirely on (hover: none) devices — touch screens have no reliable mouseenter, so no bar is injected. For the always-on underline variant that would leave the link looking like plain text, so the CSS file paints a static native text-decoration underline there instead (honouring --aa-hover-underline-thickness; the offset is left at the browser default so skip-ink steps cleanly around descenders). The link still reads as a link; only the sweep animation is dropped. underline-in gets no fallback — its rest state is intentionally line-less, so there's nothing to preserve.
Required GSAP plugins
Section titled “Required GSAP plugins”gsap.
Live demo — underline-in
Section titled “Live demo — underline-in”Each link's bar sweeps in, then back out. Flick across rapidly — the queue-up model keeps every cycle clean.
Live demo — underline (always-on)
Section titled “Live demo — underline (always-on)”The line is permanent; hover collapses it to the right edge, then re-grows it from the left. Each phase runs for half of aa-duration.
Live demo — thick underline via CSS variable
Section titled “Live demo — thick underline via CSS variable”--aa-hover-underline-thickness: 0.2em produces a heavy bar; a small positive --aa-hover-underline-offset pushes it clear of deep descenders.
Live demo — coloured underline (independent of text)
Section titled “Live demo — coloured underline (independent of text)”aa-color overrides the bar's background-color so the underline reads in a brand colour while the text stays black.
Host setup
Section titled “Host setup”The bar lives inside the host with position: absolute; bottom: 0; left: 0; width: 100% — so it lands at the bottom edge of the host's content box. Two recipes cover almost every case.
Standalone link or button (recommended)
Section titled “Standalone link or button (recommended)”For nav links, CTAs, or anything where the <a> doesn't live inside flowing paragraph text. Symmetric vertical padding adds clearance below the descenders and widens the hoverable area above the cap-height, so the cursor doesn't have to land exactly on the glyphs.
.nav-link { display: inline-block; line-height: 1; padding: 0.3em 0; color: inherit; text-decoration: none;}<a class="nav-link" href="/work" aa-hover="underline">Work</a>Inline link inside paragraph text
Section titled “Inline link inside paragraph text”Leave layout alone — the default inline <a>'s bounding box already matches the glyph extent, so the bar lands near the descender baseline. The lib auto-sets --aa-hover-underline-offset: 0.05em on every <p>, mirroring the gap browsers use for text-decoration: underline, so this works out of the box. For deep-descender fonts (g, j, y) bump the offset higher with --aa-hover-underline-offset: 0.1em on the <p> (or any ancestor).
For other block-level text containers (<li>, <blockquote>, custom <div> paragraphs), set the variable yourself to opt in:
.prose { --aa-hover-underline-offset: 0.05em; }p a { color: inherit; text-decoration: none;}