Bookmark Toggle
Notched bookmark that fills with indigo and bounces elastically when tapped, with a label going from "Save" to "Saved!".
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 bookmark is drawn in SVG: a rectangle with rounded top corners, split in a V at the bottom. The bookmark and its label sit in the same <button>: the whole area is clickable.
On click, Enter or Space, aria-pressed goes to true. The bookmark fills with indigo (#6366f1), sinks then bounces (0.4 s, cubic-bezier(.68,-.55,.265,1.55)) and stays scaled at 110 %; the label takes the data-bmk-on text and the #818cf8 colour. Another click brings back the grey and the starting label. The bounce only plays after a click, never on load for a bookmark already saved.
The label colour comes from the CSS (--bmk-label, --bmk-label-on), so it changes without touching the JavaScript. The starting state is read from aria-pressed, and every toggle fires the fx0743:change event (detail.saved) from the root, to store the favourite on the server.
Accessibility
- Name and state: the button keeps a fixed name (
aria-label="Save") and gives its state througharia-pressed: "Save, toggle button, pressed". The visible label, which changes, is hidden from screen readers so it is not read twice. - Keyboard: real
<button>, Enter and Space, lavender ring around the bookmark and label on keyboard focus. - Contrast: off bookmark
#70708cat 3.6:1 on the background; saved label#818cf8at 5.7:1. - Reduced motion: the bookmark changes colour in place, without bounce or transition.
Browser compatibility
Inline SVG, CSS and 1.7 KB of dependency-free JavaScript. Measured in Chromium 151, Firefox 153 and WebKit 26.5 (Playwright): code pasted twice (each bookmark toggles on its own), click, Space on the keyboard, touch at 390 px, reduced motion, 0 errors, no name added to window.
Without JavaScript, the grey bookmark and its label show but do not toggle. The focus ring needs :focus-visible (Chrome 86, Firefox 85, Safari 15.4); in older browsers, everything works without a ring.
The code
HTML structure to paste into your page (the CSS + JS come with your purchase):
<div class="fx-0743-root">
<div class="bmk-demo">
<button type="button" class="bmk-btn" aria-pressed="false" aria-label="Save" data-bmk-on="Saved!">
<svg class="bmk-icon" viewBox="0 0 30 40" aria-hidden="true"><path d="M4 0h22a4 4 0 0 1 4 4v36L15 28 0 40V4a4 4 0 0 1 4-4z"></path></svg>
<span class="bmk-label" aria-hidden="true">Save</span>
</button>
</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 |
|---|---|---|
Labels (HTML — text of .bmk-label and data-bmk-on) |
"Save" · "Saved!" | Text at rest and once saved; keep the button's aria-label in line with the first one. |
Already saved (HTML — aria-pressed="true") |
false |
Shows an existing favourite, with no bounce on load. |
Bookmark size (CSS — --bmk-size) |
30 px (40 px high) | The height always follows the 4/3 ratio. |
Bookmark colours (CSS — --bmk-off, --bmk-on) |
#70708c · #6366f1 |
Keep at least 3:1 with your background for the off bookmark. |
Label (CSS — --bmk-label, --bmk-label-on, --bmk-label-size, --bmk-gap) |
white at 60 % · #818cf8 · .9rem · 20 px |
Text colours and size, gap with the bookmark. |
Frame (CSS — --bmk-height, --bmk-page, --bmk-panel, --bmk-pad) |
300 px · #0a0a0f · #1a1a2e · 20 px |
0 and transparent to place it in a row or a card. |
Server (JS — fx0743:change event) |
— | detail.saved is true or false on every click: store or remove the favourite. |
FAQ
<span class="bmk-label">; the button keeps its aria-label, so it stays named. Then plan a click area of at least 24 px, for instance with --bmk-size: 24px.aria-pressed="true" for the items they already saved: the script then shows the filled bookmark and the data-bmk-on label, without playing the bounce.