Like / Heart Button
Heart-shaped Like button: on click it turns red, beats, throws five little hearts around it and adds 1 to the counter; a second click removes the like.
Updated
This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Utilities has 43 effects, including 3 free. Explore the category →
3 usage examples



How it works
The button is a real toggle button: aria-pressed goes to true on click, Enter or Space. The heart turns red (#ef4444), the button background turns pink and the heart beats (scaled to 130 %, then 90 %, then 120 %, in 0.6 s). At the same moment, five little hearts fly upwards, each in its own direction, shrink and fade in 0.6 s.
The burst is started by the lkh-burst class, which the script removes and adds back on every like: the burst replays each time. Removing the like does not fire a burst.
The counter starts from the number written in .lkh-num (42 in the sample HTML): +1 on like, −1 on removal, never below zero. The starting state is read from aria-pressed, so a like already given can be shown. Every toggle fires the fx0742:change event (detail.liked, detail.count) from the root: that is where you tell your server. Every size follows --lkh-size.
Accessibility
- Name and state: the button is called "Like" (visually hidden text) and announces "toggle button, pressed / not pressed". The drawn hearts are hidden from screen readers.
- Total announced: the counter is an
aria-live="polite"area; after a click, the screen reader says "43 likes". - Keyboard: real
<button>, Enter and Space, lavender ring on keyboard focus. - Contrast: the off heart is
#8a8aa3, 4.2:1 on the button; the red heart is about 4:1 on the pink background. The state does not rely on colour alone: it is also given byaria-pressed. - Reduced motion: no beat and no burst; the heart turns red and the counter changes, without animation.
Browser compatibility
CSS and 1.5 KB of dependency-free JavaScript. Measured in Chromium 151, Firefox 153 and WebKit 26.5 (Playwright): code pasted twice (each button counts on its own), burst invisible on load then visible 120 ms after a click (opacity 0.66 to 0.74), no burst on removal, keyboard, touch at 390 px, reduced motion, 0 errors, no name added to window.
Without JavaScript, the button stays grey and the counter does not move. The burst uses CSS variables inside @keyframes (Chrome 49, Firefox 31, Safari 9.1); the focus ring needs :focus-visible (Chrome 86, Firefox 85, Safari 15.4).
The code
HTML structure to paste into your page (the CSS + JS come with your purchase):
<div class="fx-0742-root">
<div class="lkh-demo">
<button type="button" class="lkh-btn" aria-pressed="false">
<span class="lkh-heart" aria-hidden="true">❤</span>
<span class="lkh-particles" aria-hidden="true">
<span class="lkh-particle">❤</span> (× 5)
</span>
<span class="lkh-vh">Like</span>
</button>
<span class="lkh-count" aria-live="polite" aria-atomic="true"><span class="lkh-num">42</span><span class="lkh-vh"> likes</span></span>
</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 |
|---|---|---|
Starting total (HTML — text of .lkh-num) |
42 | Write the real total from your database; only digits are read. |
Already liked (HTML — aria-pressed="true" on the button) |
false |
Shows a like already given by this visitor. |
Spoken name (HTML — text of .lkh-vh) |
"Like" · "likes" | Adapt it: "Vote for this cake", "votes". |
Size (CSS — --lkh-size, --lkh-gap) |
60 px · 20 px | Heart, burst and distances follow the button size. |
Colours (CSS — --lkh-btn, --lkh-btn-on, --lkh-off, --lkh-on) |
#2a2a3e · red at 10 % · #8a8aa3 · #ef4444 |
Button background at rest and liked, heart off and on (the burst takes the on colour). |
Counter (CSS — --lkh-count-size, --lkh-count-color) |
1.2rem · white | Darken it on a light background. |
Frame (CSS — --lkh-height, --lkh-page, --lkh-panel, --lkh-pad) |
300 px · #0a0a0f · #1a1a2e · 20 px |
0 and transparent to place it under a picture or in a list. |
Server (JS — fx0742:change event) |
— | root.addEventListener('fx0742:change', e => fetch('/api/like', { method: 'POST', body: JSON.stringify(e.detail) })). |
FAQ
fx0742:change to send the like to your server, and write the up-to-date total in .lkh-num when you build the page.fill: currentColor in place of the character.String(count) with count.toLocaleString('en-US') in the script.