motion-liquid

Applies an animated SVG displacement filter to text, giving it a living, fluid quality. It feels like ink in water or hot air shimmer. No WebGL required.

Preview

LIQUID

Import

import 'motion-components/motion-liquid'   // just this one
import 'motion-components'               // or the whole library

Usage

Static content

Write the text as a child. The browser shows it as plain text before the element is defined, so the page never paints an empty gap while the library loads.

<motion-liquid intensity="12" duration="4.5">LIQUID</motion-liquid>

Dynamic content

Use the text attribute when text changes at runtime. Setting the property restarts the animation automatically.

const el = document.querySelector('motion-liquid')
el.text = 'UPDATED'   // animation restarts

If both are present, the attribute wins and the child text stays as the pre-upgrade fallback.

Intensity

intensity sets the maximum displacement in pixels. Higher values create more dramatic distortion.

SUBTLE INTENSE
<motion-liquid intensity="5">SUBTLE</motion-liquid>
<motion-liquid intensity="24">INTENSE</motion-liquid>

Duration

duration sets the seconds per distortion cycle. Long cycles feel like a gentle shimmer. Short cycles feel chaotic. Set it to 0 to hold the text still.

SLOW FAST
<motion-liquid intensity="14" duration="18">SLOW</motion-liquid>
<motion-liquid intensity="14" duration="2.25">FAST</motion-liquid>

Pause on hover

Add pause-on-hover to freeze the fluid motion when the cursor enters.

HOVER ME
<motion-liquid intensity="14" duration="6" pause-on-hover>
  HOVER ME
</motion-liquid>

How it works

An SVG <filter> with <feTurbulence> and <feDisplacementMap> is applied to an SVG <text> element, and SMIL <animate> elements drive its baseFrequency and scale over time. Filtering SVG content (rather than an HTML element via CSS filter: url()) is what keeps it animating on WebKit/iOS, where a url() filter on HTML only repaints on scroll.

Properties

Attribute Property Type Default Description
text text string — Text to render with the liquid effect. Falls back to the child text when unset
intensity intensity number 10 Maximum displacement in px
duration duration number 4.5 Seconds per distortion cycle. Lower is faster, 0 holds the text still
pause-on-hover pauseOnHover boolean false Freeze motion on mouseenter, resume on mouseleave

JavaScript API

Control the liquid programmatically with play(), pause(), finish(), and cancel().

playState: –

Accessibility

When prefers-reduced-motion is set, the animation loop does not start and the text renders without distortion.