webdevpuneet.com

Like Button in HTML, CSS & JS — Heart Burst, Double-Tap

Like / Favorite Button · Buttons · Plain HTML, CSS & JS · Live preview

CategoryButtons

Copy & paste

Source Code

<div class="fav-demo">
  <button type="button" class="fav big" data-id="demo-like" data-base="127" data-on="Liked" data-off="Like" aria-pressed="false" style="--c:#f43f5e;--spin:0deg">
    <span class="fav-icon"><svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true"><path d="M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.29 1.49 4.04 3 5.5l7 7Z"/></svg></span>
    <span class="fav-label">Like</span>
    <span class="fav-count">128</span>
  </button>

  <div class="fav-row">
    <button type="button" class="fav mini" data-id="demo-star" data-base="1249" aria-pressed="false" style="--c:#f59e0b;--spin:-72deg">
      <span class="fav-icon"><svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true"><path d="m12 2.5 2.9 6 6.6.9-4.8 4.6 1.2 6.5-5.9-3.1-5.9 3.1 1.2-6.5L2.5 9.4l6.6-.9L12 2.5Z"/></svg></span>
      <span class="sr">Favorite</span><span class="fav-count">1.2k</span>
    </button>
    <button type="button" class="fav mini" data-id="demo-save" data-base="41" aria-pressed="false" style="--c:#818cf8;--spin:0deg">
      <span class="fav-icon"><svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true"><path d="M6 3h12a1 1 0 0 1 1 1v17l-7-4-7 4V4a1 1 0 0 1 1-1Z"/></svg></span>
      <span class="sr">Save</span><span class="fav-count">42</span>
    </button>
    <button type="button" class="fav mini liked" data-id="demo-helpful" data-base="8" aria-pressed="true" style="--c:#38bdf8;--spin:-20deg">
      <span class="fav-icon"><svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true"><path d="M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88Z"/></svg></span>
      <span class="sr">Helpful</span><span class="fav-count">9</span>
    </button>
  </div>

  <figure class="photo" id="photo">
    <div class="photo-img">
      <svg class="dbl" id="dbl" viewBox="0 0 24 24" aria-hidden="true"><path d="M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.29 1.49 4.04 3 5.5l7 7Z"/></svg>
    </div>
    <figcaption>
      <div><b>Golden hour, Lisbon</b><span>Double-tap the photo to like</span></div>
      <button type="button" class="fav mini" id="demoPhoto" data-id="demo-photo" data-base="2310" aria-pressed="false" style="--c:#f43f5e;--spin:0deg">
        <span class="fav-icon"><svg viewBox="0 0 24 24" width="18" height="18" aria-hidden="true"><path d="M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.29 1.49 4.04 3 5.5l7 7Z"/></svg></span>
        <span class="sr">Like photo</span><span class="fav-count">2.3k</span>
      </button>
    </figcaption>
  </figure>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Four icon variants
Heart, star, bookmark and thumb share one handler, each coloured by its own --c property.
Spring pop with rotation
An overshooting cubic-bezier keyframe, starting from each button's --spin angle, makes the star twist and the heart bounce.
Colour-matched burst
Twelve particles use the button's colour, a lighter mix and white, all removed on animationend.
Drift-free count
A data-base number plus your own like gives the count, so abbreviated values like 1.2k still change on every tap.
Directional count roll
The number slides up when liked and down when un-liked, restarted with a reflow so fast taps still animate.
Saved in localStorage
State is restored on load per data-id, and every storage call is guarded so blocked storage never breaks the buttons.
Double-tap to like
Two clicks within 320ms pop a large heart over the photo and like it without ever un-liking.
Accessible and motion-aware
Buttons use aria-pressed with hidden names, coloured focus rings and a reduced-motion path.

About this UI Snippet

Like / Favorite Button — Particle Burst, Four Icon Variants, Saved State and Double-Tap

Screenshot of the Like / Favorite Button snippet rendered live

The like button is one of the most-tapped controls on the web, and the difference between a flat colour change and a good one is a few hundred milliseconds of feedback. This snippet is a complete set built in plain HTML, CSS and vanilla JavaScript: a primary Like pill, compact Favorite, Save and Helpful buttons, and a photo card that likes on double-tap. Each tap springs the icon, fires a radial burst in the button's own colour and rolls the count; the liked state is remembered in localStorage, and none of it needs a library.

One handler, four personalities

Every button is the same .fav element with its own --c colour and --spin angle set inline. The liked style is color-mix of that colour, so a rose heart, amber star, indigo bookmark and sky-blue thumb all share one stylesheet. The pop keyframe starts rotated by --spin, which makes the star twist into place while the heart simply grows. Adding a fifth variant is a new button with a new colour and SVG path.

Spring pop, burst and ring

When .liked is added, the icon fills and a keyframe overshoots from scale(.2) to 1.35 and settles, with a cubic-bezier(.2,1.6,.4,1) curve. burst() then adds twelve particles at evenly spaced angles with random jitter, writes each target as --tx and --ty, and tints them with the button's colour, a lighter mix of it and white. A ring expands behind them. All of them remove themselves on animationend, so repeated taps never leave nodes behind. Un-liking is quiet: no burst, just the count rolling down.

A count that never drifts

The old approach parsed the displayed text, so "1.2k" plus one stayed "1.2k". Here each button stores a data-base number, the count excluding your own like, and render() always shows base + (liked ? 1 : 0). Liking then un-liking can never leave the number off by one. The count slides up when you like and down when you un-like, restarted with a forced reflow so rapid taps still animate.

Remembered state

setLiked() writes fav-<id> to localStorage and the page restores it on load before anything animates. Every access is wrapped in try/catch, because storage can be blocked, and the buttons still work without it. For real data, replace save() with a request to your API.

Double-tap to like

The photo card counts two clicks within 320ms as a double-tap, pops a large heart over the image and likes the linked button. Like Instagram, double-tap never un-likes. The same logic works with touch and mouse.

Accessibility and motion

Each toggle is a real button with aria-pressed, and icon-only buttons carry a visually hidden name such as "Favorite". Focus rings take the button's colour. With prefers-reduced-motion, the pop, roll and burst are skipped, while the count and pressed state still update.

Step by step

How to Use

  1. 1
    Paste HTML, CSS and JSA large Like pill, three compact buttons (the Helpful one already liked) and a gradient photo card appear on a dark background.
  2. 2
    Tap the big heartThe heart fills, springs, fires twelve rose-coloured particles and a ring, the label changes to "Liked" and the count slides up to 128.
  3. 3
    Tap it againThe icon resets quietly and the count slides down, with no burst when un-liking.
  4. 4
    Try the star, bookmark and thumbEach uses its own colour and starts its pop with a different rotation. The star's count moves from 1.2k to 1.3k when liked, and back again when un-liked.
  5. 5
    Double-tap the photoA large heart pops over the image and the corner button likes. Double-tapping again does not un-like.
  6. 6
    Reload the pageYour choices are restored from localStorage under fav-<id>, so give every button a unique data-id.

Real-world uses

Common Use Cases

Social feed reactions
Use the Like pill and the double-tap photo in a social post card or an activity feed, with data-id set to the post id.
Product wishlist
Put the heart in the corner of a product card, where the saved state makes a returning shopper's favourites appear already filled.
Article and doc bookmarks
The indigo Save button fits a reading list or docs page, using the same burst and count with a bookmark icon.
Helpful votes on reviews
The thumb variant works for "Helpful" counts in a comment thread, where un-voting must reduce the number by exactly one.
Media favourites
Add a star to a track or video row, for example in a music player control bar, and save it per item id.

Got questions?

Frequently Asked Questions

Displayed counts are often abbreviated, so "1.2k" plus one is still "1.2k" and the number drifts after several taps. Storing the count without your own like as data-base and always showing base plus one when liked keeps it exact, and un-liking returns to the original number.

Replace save() with a request, and update the UI first. If the request fails, call setLiked() again with the previous value to revert the icon and the count. Pass the server's total as the new data-base when it returns.

The photo remembers the time of the last click. A second click within 320ms counts as a double-tap, shows the big heart and likes the button once if it is not already liked. Single taps do nothing, so scrolling and links are unaffected.

Keep liked state and a base count per item, render count as base plus one when liked, and toggle a class for the pop. Spawn the burst from a ref in the click handler or an effect. The CSS, including the --c and --spin custom properties, moves over unchanged.