Navigation✨ Premium

Footnote Popover

Superscript reference markers reveal a content bubble anchored above the marker, animated with opacity and scale — pure CSS, zero JavaScript.

CSSHoverPopover

You'll get access to the interactive demo with a free account.

This effect is part of Effect.Labs — 811 vanilla effects, some free, some premium. Navigation has 36 effects, including 4 free. Explore the category →

3 usage examples

Technical blog post — inline footnotes — Footnote Popover example 1

① Technical blog post — inline footnotes

WhenA long-form blog post with bibliographic references, source links, or technical term definitions embedded in the body text.
WhyThe popover anchored to the marker avoids scrolling to the bottom or opening a new tab — the note appears right where the reader is, without breaking reading flow.
SettingsPopover width at 240px (set in .fn-popover { width }), font size .75rem, badge color adapted to the article's palette.
UI component card — inline contextual help — Footnote Popover example 2

② UI component card — inline contextual help

WhenA component documentation sheet (design system, Storybook, API reference) where each property or parameter can carry an explanatory marker directly in the table.
WhyThe popover stays within the table flow and does not shift the layout — the developer understands the property without leaving the view, reducing context switches.
SettingsBadge 16px × 16px, font 0.6rem, popover centered on badge, light-theme popover background (#f1f5ff, text #1e1b4b).
Cosmetic product card — Annotated certified INCI ingredients — Footnote Popover example 3

③ Cosmetic product card — Annotated certified INCI ingredients

WhenAn e-commerce product page lists the INCI ingredients of a skincare item; each certified or declared allergen ingredient carries a numbered marker directly in the list.
WhyThe popover reveals the exact regulatory source or certification (COSMOS, REACH, IFRA) without cluttering the list — the customer checks in one hover what they would otherwise leave the page to find.
SettingsBadge reduced to 14×14px, font-size: .55rem to fit the compact typography of an INCI list; popover at 240px, background #1e1b4b (default), bottom: calc(100% + 8px).

How it works

The effect is entirely CSS-driven, with no JavaScript. Each .fn-ref marker is an inline-flex badge in position: relative, and its .fn-popover child is position: absolute with bottom: calc(100% + 10px) — anchoring it exactly 10 px above the badge, centered horizontally via left: 50%; transform: translateX(-50%).

Visibility is controlled by the descendant selector .fn-ref:hover .fn-popover: at rest, the popover has opacity: 0, transform: translateX(-50%) scale(0.95), and pointer-events: none; on hover, it switches to opacity: 1, scale(1), and pointer-events: auto — the dual CSS transition (opacity .2s, transform .2s) produces a fade-and-scale entrance with no RAF or JS.

The arrow pointing at the marker is drawn by the .fn-popover::after pseudo-element using the border trick: a zero-size square whose borders form an isosceles triangle (border-color: #1e1b4b transparent transparent), placed at top: 100% and centered. The popover background (#1e1b4b) and the triangle color are identical, visually aligning the arrow with the bubble.

The badge gets a background of rgba(99,102,241,.2) rising to rgba(99,102,241,.4) on hover (transition: background .2s), and uses vertical-align: super to sit naturally in text flow like a superscript. The popover is declared pointer-events: none at rest to avoid hover conflicts on adjacent areas.

Accessibility

  • prefers-reduced-motion not handled: the code includes no @media (prefers-reduced-motion: reduce) block — opacity and scale CSS transitions fire even when the OS signals a reduced-motion preference. Add the block if deploying on a public-facing site.
  • Keyboard interaction not covered: the popover is triggered only by CSS :hover — keyboard users (Tab navigation) cannot see the content. To cover the keyboard, add tabindex="0" to .fn-ref and use the :focus-within selector.
  • No aria- attributes on markers or popovers — note content is invisible to screen readers. Add role="button", aria-describedby, or aria-haspopup if the content is essential.
  • Text contrast: popover text color (#c7d2fe on #1e1b4b background) exceeds the WCAG AA 4.5:1 ratio — secondary text remains readable.
  • The badge (#818cf8 on rgba(99,102,241,.2)) is decorative (short numeral); its translucent background falls below the AA ratio, but a single digit is not critical content.

Browser compatibility

Uses only CSS2/CSS3 selectors and transitions — no polyfill required.

Chrome 80+✓ Full
Firefox 78+✓ Full
Safari 14+✓ Full
Edge 80+✓ Full
Mobile iOS✓ Tap to show
Android Chrome✓ Tap to show

If CSS transitions are unsupported, the popover appears and hides instantly on hover — no errors, content remains accessible.

The code

HTML structure to paste into your page (CSS + JS available with a premium account):

index.html — structure
<div class="anchor-demo">
  <div class="footnote-scene">
    <div class="footnote-text">
      Text with reference
      <span class="fn-ref">1
        <span class="fn-popover">
          <span class="fn-num">[1]</span> Note content.
        </span>
      </span>
      rest of text.
    </div>
  </div>
</div>
🔒 Unlock the full code — from €2.99 the first month

Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
.fn-popover { width } 220px Bubble width — increase for longer notes, decrease for short definitions. Recommended range: 180–300px.
.fn-popover { bottom } calc(100% + 10px) Vertical gap between the bottom of the popover and the top of the badge. Increase the offset (e.g. 14px) if your font is large and popovers overlap.
.fn-popover (background) #1e1b4b Bubble background color. Must match the ::after triangle color to avoid a visual seam.
.fn-popover::after (border-color) #1e1b4b transparent transparent Triangle color pointing to the badge — keep it identical to the popover background.
.fn-ref (background / hover background) rgba(99,102,241,.2) / .4 Badge background at rest and on hover. Adjust opacity or color to match your brand palette.
.fn-popover (transition) opacity .2s, transform .2s Duration and easing of the enter/exit animations. Switch to .15s for a snappier appearance, or .3s ease-in-out for a softer fade.
.fn-popover (font-size) .72rem Font size of popover content. Keeps text discreet — do not exceed .85rem to stay within the typographic hierarchy.
.fn-ref { transform: scale } scale(0.95) → scale(1) Scale animation amplitude on entry. Reduce to scale(0.98) for a subtler effect, or remove the transform property entirely to disable the scale animation.

FAQ

Add tabindex="0" to each .fn-ref and extend the CSS selector: .fn-ref:hover .fn-popover, .fn-ref:focus-within .fn-popover { opacity: 1; transform: translateX(-50%) scale(1); pointer-events: auto; }. For screen readers, add role="button" to .fn-ref and aria-describedby pointing to the popover's id.
The popover is centered on the badge by default. If the badge is near an edge, replace left: 50%; transform: translateX(-50%) with right: 0; transform: translateX(0) (or left: 0 for the left edge), and move the ::after arrow with left: auto; right: 8px. For automatic handling, a short JS snippet reading getBoundingClientRect() and toggling a CSS class is enough.
No — the position: absolute popover is clipped by any ancestor with overflow: hidden or overflow: clip. The simplest fix is to set the container to overflow: visible. If that is not possible (e.g. carousel, scrolling table), move the popover out of the flow with position: fixed and reposition it via JavaScript using the badge's getBoundingClientRect() coordinates.