Hover✨ Premium

Magnetic Letters

Eight letters on a dark background drift toward the cursor when it comes within 100 px, then spring back to their place; a click reverses direction and repels them. Force is proportional to distance — the closer the cursor, the stronger the attraction (or repulsion).

JSPhysicsText

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Hover has 48 effects, including 5 free. Explore the category →

3 usage examples

Hero headline for a tech conference page — Vordyne 2027 — Magnetic Letters example 1

① Hero headline for a tech conference page — Vordyne 2027

WhenConference landing page (Vordyne 2027): the event name as a large magnetic headline that draws attention on hover.
WhyAn animated hero captures attention and conveys the conference's promise (technology, interaction) before the visitor reads a single line.
SettingsExtra-bold 3.8 rem font, white colour on dark background (gradient #060614 → #0e0a2a), attraction mode by default; influence radius kept at 100 px to cover the full hero area.
Gamified quiz score — web development microlearning platform — Magnetic Letters example 2

② Gamified quiz score — web development microlearning platform

WhenThe final score "1200" is displayed as large magnetic letters; on click, digits switch to repulsion mode and flee the cursor — the user must "chase their score" to see it, anchoring the moment.
WhyAn unexpected interaction makes the score reveal memorable; repulsion creates a spontaneous mini-game that extends engagement after the quiz is submitted.
SettingsDigits in accent colour (golden yellow), dark background; repulsion mode is triggered by a synthetic click on load to demonstrate this use case immediately.
Magnetic logo in the navigation bar — Drael product page — Magnetic Letters example 3

③ Magnetic logo in the navigation bar — Drael product page

WhenHeader of a SaaS product page (Drael): the 5-letter wordmark in the navigation bar reacts to cursor hover, keeping brand identity alive without leaving the nav.
WhyA magnetic logo in the nav is an interactive brand signal at small scale — letters respond subtly without disrupting the readability of nav links.
Settings5 letters at 2 rem · white on dark background · attract mode · inside a real nav with links and CTA

How it works

Each letter is a <span class="ml379-letter"> inside the .ml379-container. On every frame of a requestAnimationFrame loop, the script computes the distance between each letter's centre and the mouse position in the container's coordinate system. If the distance is below 100 px, the letter is offset by a translate(dx, dy) whose magnitude is distance × force × 0.5 × direction: force is (100 − dist) / 100, so 1 at the cursor and 0 at 100 px. Direction is +1 (attraction) or −1 (repulsion) depending on the current state, toggled on each click on the container. When the mouse is more than 100 px away or outside the container, the letter returns to translate(0, 0) via the CSS transition: transform 0.1s ease-out.

Each letter's colour shifts from #6366f1 (at rest) to hsl(280 + i × 15, 70%, 60%) when inside the influence zone, with i its rank in the list (violet to pink). When the cursor leaves the container, mouseleave snaps all letters back instantly. The touchmove event (with preventDefault()) provides the same behaviour on a touchscreen. An IntersectionObserver pauses the loop when the effect is off screen.

Accessibility

  • Role and label: the container has role="img" and aria-label="MAGNETIC"; the eight letters have aria-hidden="true". A screen reader announces "MAGNETIC" once and ignores the letter movement.
  • Keyboard focus: the container has tabindex="0" and a :focus-visible outline (2 px indigo). On focus, the mouse is virtually placed at the container's centre, triggering attraction on the middle letters; on blur, the letters return to their place.
  • Touch: touchmove moves letters toward the finger exactly like the mouse. touchend resets them. Page scrolling is blocked (preventDefault) while the finger is inside the container.
  • Reduced motion: under prefers-reduced-motion: reduce, the loop does not start and transition: none is forced on the letters; they stay still, the label is always readable.
  • Click: a click toggles between attraction and repulsion. No button role is added on the container (role="img" takes priority); if the toggle is functional in your context, replace the role with role="button" and add a keydown handler for Enter/Space.

Browser compatibility

Pure DOM and CSS, no dependency. IntersectionObserver available since Chrome 51, Firefox 55, Safari 12.1. requestAnimationFrame since Chrome 10, Firefox 11, Safari 6. CSS transitions and window.matchMedia cover all modern browsers. Not verified on real Safari; expected full.

Chrome 51+✓ Full (measured)
Firefox 55+✓ Full (measured)
Safari 12.1+✓ Expected full (not measured)
Edge 79+✓ Full (measured)
Mobile iOS 12.2+✓ Full on touch (not measured)
Android Chrome 51+✓ Full on touch (not measured)

Without JavaScript, letters display statically with no behaviour. Without IntersectionObserver, the loop also runs off screen.

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0379-root">
  <div class="ml379-container" role="img" aria-label="MAGNETIC" tabindex="0">
    <span class="ml379-letter" aria-hidden="true">M</span>
    <span class="ml379-letter" aria-hidden="true">A</span>
    <span class="ml379-letter" aria-hidden="true">G</span>
    <span class="ml379-letter" aria-hidden="true">N</span>
    <span class="ml379-letter" aria-hidden="true">E</span>
    <span class="ml379-letter" aria-hidden="true">T</span>
    <span class="ml379-letter" aria-hidden="true">I</span>
    <span class="ml379-letter" aria-hidden="true">C</span>
  </div>
  <span class="ml379-label" aria-hidden="true">Move the mouse near the letters</span>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Influence radius (JS — if(dist < 100)) 100 px 60 px gives a more precise, less intrusive effect; 150 px pulls letters from halfway across the container.
Displacement intensity (JS — force * 0.5) 0.5 0.8 makes the movement more dramatic; 0.2 gives a barely perceptible breath.
Default mode (JS — var isAttract = true) attraction Initialise to false to start in repulsion.
Letter text (HTML — eight <span class="ml379-letter">) MAGNETIC (8 letters) Replace with any word of 4 to 12 letters; beyond 10, reduce the font to 1.8 rem to avoid overflow on mobile.
Return speed (CSS — transition: transform 0.1s) 0.1 s 0.3 s gives a lazy return; 0.04 s a near-instant snap.

FAQ

Yes. Replace role="img" with role="button", add aria-label="Toggle attraction / repulsion" and a keydown handler that calls the toggle on Enter and Space. Make sure the :focus-visible outline stays visible.
Force depends on the distance from each letter to the cursor. The closest letters experience maximum force; those right at the 100 px edge barely move. That gradient is what gives the impression of a magnetic field rather than a uniform shift.
Yes. The script iterates over all span.ml379-letter elements it finds in the container. On mobile at 390 px, 10 letters at 2.5 rem fit on one line without overflow; beyond that, flex-wrap sends them to a second row, shifting their centres and giving a two-level effect.