Pulse / Heartbeat
An SVG heart beating in a double pulse, surrounded by two rings that widen and fade — pure CSS, with a setting to stop and restart it.
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 fits in an 80 × 80 unit SVG: a red #ef4444 <path class="hrtb-heart"> and two .hrtb-ring circles of radius 20, unfilled, with a 2-unit stroke, sharing the same center.
The heart follows @keyframes hrtbBeat: it grows to 115% on the first beat (15% of the cycle), settles, then to 110% on the second beat (45%), a "lub-dub", and rests until the end of the 1.2 s cycle. Each ring follows hrtbRing: it starts at 80% of its size and 80% opacity and grows to 180% while fading out; the second ring starts a quarter cycle after the first. Both animations derive from a single variable, --hrtb-speed: changing the pace keeps heart and rings in sync.
Add the data-hrtb-idle attribute on .fx-0606-root to stop the beat (still heart, rings hidden); remove it to start again, for instance after a click. No JavaScript is shipped: animation and class names are prefixed hrtb, so they don't mix with another beating heart on the page.
Accessibility
- Decorative: the SVG has
aria-hidden="true"andfocusable="false". The meaning (a support recorded, a staff pick) must be in visible text, like the button label in the first example. - Reduced motion: under
prefers-reduced-motion: reduce, the heart stops beating and a single ring stays visible, still and faint (35% opacity, 130% size): the drawing keeps its halo with nothing pulsing. - Safe pace: one beat every 1.2 s (50 per minute), far from risky flashing rates; no sudden brightness change.
- Interaction is up to you: the effect captures neither clicks nor keys. For a "Like", put it inside a real
<button aria-pressed>and toggledata-hrtb-idleon click.
Browser compatibility
CSS animations (transform: scale on SVG elements), CSS variables inside animation and calc() on a duration, prefers-reduced-motion. Measured in Chromium, Firefox and WebKit (Playwright): 0 errors, three animations named hrtbBeat / hrtbRing, no animation with data-hrtb-idle, frozen rendering under reduced motion, two independent copies.
Without CSS animations, the red heart stays visible and still, and the rings stay invisible.
The code
HTML structure to paste into your page (the CSS + JS come with your purchase):
<div class="fx-0606-root">
<div class="hrtb-stage">
<svg class="hrtb-svg" viewBox="0 0 80 80" aria-hidden="true" focusable="false">
<circle class="hrtb-ring" cx="40" cy="40" r="20"/>
<circle class="hrtb-ring" cx="40" cy="40" r="20"/>
<path class="hrtb-heart" d="…"/>
</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 — --hrtb-size) |
80px | Side of the drawing; 100% follows the parent's width. At their largest the rings slightly exceed the heart: leave a little room around it. |
Color (CSS — --hrtb-color) |
#ef4444 | Heart and rings together (white on a colored button, for instance). |
Pace (CSS — --hrtb-speed) |
1.2s | Length of one full beat; 60 / length = beats per minute (0.8s ≈ 75 per minute). The second ring's offset follows automatically. |
Stop / restart (HTML — data-hrtb-idle attribute on .fx-0606-root) |
absent (the heart beats) | Present: still heart, rings hidden. Toggle it in JavaScript to make the heart beat only after an action. |
Block background and height (CSS — --hrtb-page, --hrtb-root-h) |
#0a0a0f / 300px | transparent and 0px to slip the heart into a button, a badge or a heading. |
FAQ
data-hrtb-idle on the root in the HTML, then remove it on click: root.removeAttribute('data-hrtb-idle'). To stop it again, root.setAttribute('data-hrtb-idle', ''). CSS does the rest; no script is shipped.--hrtb-speed: calc(60s / 90) (about 0.67 s). You can change it live from your data with root.style.setProperty('--hrtb-speed', …).hrtbBeat and hrtbRing, and every class is prefixed hrtb: nothing carries a generic name such as heartbeat or .heart that could clash with another effect.