Wave Path
A gradient wavy line that gently swings while dashes run along it — stretchable to full width or to a simple underline without losing its stroke thickness.
Updated
This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. SVG has 30 effects, including 3 free. Explore the category →
3 usage examples



How it works
The drawing is a 220 × 80 unit SVG holding the same wave twice (four arches, from x = 10 to x = 210): .wavp-bg, a faint solid line (indigo at 20%), and .wavp-line on top, in 20-by-10 dashes colored by a horizontal gradient indigo #6366f1 → violet #8b5cf6 → magenta #d946ef.
Two motions overlap. The dashes run along the curve thanks to @keyframes wavpDash (the dash offset goes from 0 to −30 in 1 s, looping). And the wave itself swings: a SMIL <animate attributeName="d"> flips the first arch (control point from y = 10 to y = 70), the following arches follow by symmetry, back and forth in 2 s with a soft start and end. The same swing is applied to the faint line so dashes and background stay on top of each other.
The SVG stretches to any box (preserveAspectRatio="none") and the stroke keeps its 4 px thanks to vector-effect: non-scaling-stroke: the same wave works as a large full-width swell or as a 16 px tall underline. The small script gives each copy its own gradient (wavp-grad-1, -2…), so a hidden copy doesn't take the others' gradient with it, and handles reduced motion.
Accessibility
- Decorative: the SVG has
aria-hidden="true"andfocusable="false". Used as an indicator ("Recording"), pair it with visible text, as in the second example. - Reduced motion: with
prefers-reduced-motion: reduce, the CSS stops the running dashes and the script pauses the SMIL swing at its starting position: a still wave of gradient dashes remains. The setting is followed live. - Hover and keyboard: the effect reacts to nothing by itself. As a link underline, show it on the link's
:hoverand:focus-visible, so keyboard navigation gets the same cue. - Gentle pace: 2 s swing, steady dash flow, no blinking.
Browser compatibility
SMIL <animate> on the d attribute, CSS animation of stroke-dashoffset, vector-effect: non-scaling-stroke, stop-color in CSS, pauseAnimations(), prefers-reduced-motion. Measured in Chromium, Firefox and WebKit (Playwright): 0 errors, two copies with two distinct gradients, 2nd copy still colored when the 1st is hidden, wave that swings in all three engines, frozen frames under reduced motion.
Without SMIL, the wave stays still and only the dashes run. Without JavaScript, a single copy per page renders correctly; with several copies, they share the first one's gradient.
The code
HTML structure to paste into your page (the CSS + JS come with your purchase):
<div class="fx-0608-root">
<div class="wavp-stage">
<svg class="wavp-svg" viewBox="0 0 220 80" preserveAspectRatio="none" aria-hidden="true" focusable="false">
<defs>
<linearGradient id="wavp-grad" gradientUnits="userSpaceOnUse" x1="10" y1="0" x2="210" y2="0">
<stop class="wavp-c1" offset="0"/>
<stop class="wavp-c2" offset=".5"/>
<stop class="wavp-c3" offset="1"/>
</linearGradient>
</defs>
<path class="wavp-bg" d="…"><animate attributeName="d" dur="2s" …/></path>
<path class="wavp-line" stroke="url(#wavp-grad)" d="…"><animate attributeName="d" dur="2s" …/></path>
</svg>
</div>
</div>
One-time payment, no subscription — the code is yours forever
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
Size (CSS — --wavp-w / --wavp-h) |
200px / 73px | The wave stretches to the given box, the stroke stays at 4 px. 100% / 24px gives a thin full-width line. |
Gradient (CSS — --wavp-c1, --wavp-c2, --wavp-c3) |
#6366f1 / #8b5cf6 / #d946ef | Left, middle and right colors of the dashes. |
Background line (CSS — --wavp-trace) |
rgba(99,102,241,.2) | The faint wave visible between dashes; transparent to keep only the dashes. |
Dash flow (CSS — --wavp-flow) |
1s | Time to move by one dash; shorter = faster. |
Wave swing (HTML — dur of both <animate> tags) |
2s | Use the same value on both tags so the faint line and the dashes stay aligned. |
Block background and height (CSS — --wavp-page, --wavp-root-h) |
#0a0a0f / 300px | transparent and 0px to place the wave under a heading, in a button or under a link. |
FAQ
d attribute, which Safari supports like Chrome and Firefox; the CSS d property does not exist in Safari, which is why it is not used.position:absolute; left:0; right:0; bottom:0), with --wavp-w:100%, --wavp-h:16px, --wavp-page:transparent and --wavp-root-h:0px, at opacity:0; set it to 1 on :hover and :focus-visible. The stroke keeps its 4 px even when flattened.