Variable font animation
Also called kinetic text, variable font hover, or font weight animation
Animating the axes of a variable font, such as weight, width, or slant, so letters thicken, stretch, or lean smoothly, often following the pointer.
import { useRef } from 'react';
import {
motion,
useMotionValue,
useReducedMotion,
useSpring,
useTransform,
type MotionValue
} from 'motion/react';
// Needs a variable font, such as Inter from next/font with no weight list.
const RADIUS = 150; // px of reach on each side of the pointer
const MIN = 100; // the font's wght axis range
const MAX = 900;
function Letter({ char, x }: { char: string; x: MotionValue<number> }) {
const ref = useRef<HTMLSpanElement>(null);
// Heaviest right under the pointer, falling off along a cosine curve.
const settings = useTransform(x, (pointer) => {
const el = ref.current;
const distance = el
? Math.abs(pointer - el.offsetLeft - el.offsetWidth / 2)
: RADIUS;
const t = Math.min(distance / RADIUS, 1);
return `'wght' ${Math.round(MIN + (MAX - MIN) * (0.5 + Math.cos(t * Math.PI) / 2))}`;
});
return (
<motion.span ref={ref} aria-hidden style={{ fontVariationSettings: settings }}>
{char}
</motion.span>
);
}
export function WeightWord({ word }: { word: string }) {
const reduceMotion = useReducedMotion();
// Parked far to the left, so every letter starts at the lightest weight.
const pointerX = useMotionValue(-1000);
const x = useSpring(pointerX, { stiffness: 260, damping: 32 });
if (reduceMotion) return <h1 className='text-8xl'>{word}</h1>;
return (
// Letters measure offsetLeft from this positioned heading.
<h1
aria-label={word}
onPointerMove={(e) =>
pointerX.set(e.clientX - e.currentTarget.getBoundingClientRect().left)
}
onPointerLeave={() => pointerX.set(-1000)}
className='relative flex text-8xl'
>
{[...word].map((char, i) => (
<Letter key={i} char={char} x={x} />
))}
</h1>
);
}Make the hero word "Variable" react to the pointer with a variable font: load Inter as a variable font (wght 100 to 900), split the word into letter spans, and on pointer move set each letter's font-variation-settings to a 'wght' between 100 and 900 based on its horizontal distance from the pointer, using a cosine falloff over 150px and a spring to smooth the pointer. Keep the word as one aria-label, and hold every letter at 400 when prefers-reduced-motion is set.
Paste into Layerwise or any AI coding tool.
What is Variable font animation?
A variable font packs a whole family into one file, with axes you can set to any value in between: weight (wght), width (wdth), slant (slnt), optical size (opsz), and sometimes custom ones. Because those values are continuous, CSS transitions and JavaScript can animate them. A common version sets each letter's weight from its distance to the pointer, so a heavy bulge travels through the word.
It suits hero words, logos, interactive posters, and portfolio headings, where the type itself is the visual. A narrower range, such as 300 to 700, also works as hover feedback on large links.
Check that the font really is variable and which axes it ships: many web fonts have only wght, and a static font jumps between its few weights. With next/font, leaving out the weight option loads the variable file. Heavier or wider letters take more room, so the line reflows on every frame; keep it to one short word and center it. Keep the word as one accessible label, and hold a still weight when someone prefers reduced motion.
Often confused with
- Split text animation
- Split text animates each letter's position or opacity as it enters. Variable font animation changes the shape of the letters themselves.
Related terms
All termsSplit text animation
A text animation that breaks a heading into characters, words, or lines and animates each piece in turn, so the text arrives as a wave.
Hover effect
A visual change, such as a lift, glow, or zoom, that happens when the mouse pointer moves over an element to show it can be clicked.
Typographic hierarchy
Using differences in text size, weight, and color so people can tell at a glance what to read first, second, and last.
Magnetic button
A button that leans toward the mouse pointer as it gets close, then springs back when the pointer leaves.
Build it with Layerwise
Describe your app, watch it run in a live preview, and publish it with a database, storage, and sign-in built in.