Button Library · Signature
Sticky Note
A handwritten note on a stack; a click peels it off to the next one.
States
Default
Hover
Active
Focus
Code
sig-sticky.html
<button class="btn-sig-sticky" type="button"> <span class="btn-sig-sticky__under" aria-hidden="true"></span> <span class="btn-sig-sticky__note">Call Amma!</span> </button>
sig-sticky.css
.btn-sig-sticky {
--btn-bg: #ffe066;
--btn-fg: #3b3320;
--btn-font: inherit;
--btn-size: 15px;
--btn-weight: 600;
--btn-w: 132px;
--btn-h: 118px;
--btn-bw: 0px;
--btn-line: #8b6cff;
--btn-radius: 0px;
--btn-speed: 180ms;
}
.btn-sig-sticky {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 0.5em;
box-sizing: border-box;
width: var(--btn-w);
height: var(--btn-h);
padding: 0;
font-family: var(--btn-font);
font-size: var(--btn-size);
font-weight: var(--btn-weight);
line-height: 1.2;
color: var(--btn-fg);
background: none;
border: var(--btn-bw) solid var(--btn-line);
border-radius: var(--btn-radius);
box-shadow: none;
cursor: pointer;
text-decoration: none;
white-space: normal;
transition: all var(--btn-speed) ease;
isolation: isolate;
}
.btn-sig-sticky:focus-visible {
outline: 2px solid var(--btn-bg);
outline-offset: 2px;
}
.btn-sig-sticky:disabled {
opacity: 0.5;
pointer-events: none;
}
.btn-sig-sticky__icon {
width: 1.15em;
height: 1.15em;
flex-shrink: 0;
}
.btn-sig-sticky[data-state=stamped] {
--peel: btn-peel 620ms ease-in both;
}
.btn-sig-sticky__under {
position: absolute;
inset: 0;
background: #9be7c4;
transform: rotate(2deg);
box-shadow: 0 3px 6px rgba(0,0,0,.3);
}
.btn-sig-sticky__note {
position: relative;
display: grid;
place-items: center;
width: 100%;
height: 100%;
padding: 10px;
box-sizing: border-box;
font-family: 'Segoe Print', 'Bradley Hand', cursive;
background: linear-gradient(170deg, color-mix(in srgb, var(--btn-bg) 86%, #fff), var(--btn-bg) 40%, color-mix(in srgb, var(--btn-bg) 90%, #000));
border-bottom-right-radius: 26px 6px;
box-shadow: 1px 5px 6px rgba(0,0,0,.28);
transform-origin: 0 0;
transform: rotate(-2deg);
animation: var(--peel, none);
}
@keyframes btn-peel {
0% { transform: rotate(-2deg); opacity: 1; }
100% { transform: translate(34px, 46px) rotate(26deg); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
.btn-sig-sticky,
.btn-sig-sticky__note {
animation: none !important;
transition: none !important;
}
}
sig-sticky.js
document.querySelectorAll(".btn-sig-sticky").forEach((el) => {
const land = () => {
el.removeAttribute("data-state");
void el.offsetWidth;
el.dataset.state = "stamped";
};
const clear = () => el.removeAttribute("data-state");
el.addEventListener("click", land);
el.addEventListener("animationend", clear);
return () => {
el.removeEventListener("click", land);
el.removeEventListener("animationend", clear);
};
});
sig-sticky.tsx
import { useEffect, useRef } from "react";
import type React from "react";
import "./sig-sticky.css"; // the CSS tab
function attach(el: HTMLElement) {
const land = () => {
el.removeAttribute("data-state");
void el.offsetWidth;
el.dataset.state = "stamped";
};
const clear = () => el.removeAttribute("data-state");
el.addEventListener("click", land);
el.addEventListener("animationend", clear);
return () => {
el.removeEventListener("click", land);
el.removeEventListener("animationend", clear);
};
}
export function BtnSigSticky({ children = "Call Amma!", ...props }: React.ComponentProps<"button">) {
const ref = useRef<HTMLButtonElement>(null);
useEffect(() => attach(ref.current!), []);
return (
<button className="btn-sig-sticky" type="button" ref={ref} {...props}>
<span className="btn-sig-sticky__under" aria-hidden="true" />
<span className="btn-sig-sticky__note">{children}</span>
</button>
);
}
sig-sticky.html
<button class="btn-sig-sticky relative inline-flex items-center justify-center gap-[0.5em] [box-sizing:border-box] w-[132px] h-[118px] [padding:0] [font-family:inherit] text-[15px] font-[600] [line-height:1.2] text-[#3b3320] [background:none] [border:0px_solid_#8b6cff] rounded-[0px] [box-shadow:none] cursor-pointer no-underline [white-space:normal] [transition:all_180ms_ease] isolate focus-visible:[outline:2px_solid_#ffe066] focus-visible:[outline-offset:2px] disabled:[opacity:0.5] disabled:[pointer-events:none] [&[data-state=stamped]]:[--peel:btn-peel_620ms_ease-in_both] motion-reduce:[transition:none!important]" type="button">
<span class="absolute [inset:0] bg-[#9be7c4] [transform:rotate(2deg)] [box-shadow:0_3px_6px_rgba(0,0,0,.3)]" aria-hidden="true"></span>
<span class="relative grid [place-items:center] w-[100%] h-[100%] [padding:10px] [box-sizing:border-box] [font-family:'Segoe_Print',_'Bradley_Hand',_cursive] [background:linear-gradient(170deg,_color-mix(in_srgb,_#ffe066_86%,_#fff),_#ffe066_40%,_color-mix(in_srgb,_#ffe066_90%,_#000))] [border-bottom-right-radius:26px_6px] [box-shadow:1px_5px_6px_rgba(0,0,0,.28)] [transform-origin:0_0] [transform:rotate(-2deg)] [animation:var(--peel,_none)] motion-reduce:[animation:none!important]">Call Amma!</span>
</button>
<!-- A class cannot hold keyframes: keep this in your CSS. -->
<style>
@keyframes btn-peel {
0% { transform: rotate(-2deg); opacity: 1; }
100% { transform: translate(34px, 46px) rotate(26deg); opacity: 0; }
}
</style>
<!-- Needs the script from the JS tab. -->