Button Library · Signature
Receipt Printer
A click prints a torn paper strip out of the slot, line by line.
States
Default
Hover
Active
Focus
Code
sig-receipt.html
<button class="btn-sig-receipt" type="button">
<span class="btn-sig-receipt__word">Print bill</span>
<span class="btn-sig-receipt__slot" aria-hidden="true">
<span class="btn-sig-receipt__paper">PAID ₹499</span>
</span>
</button>
sig-receipt.css
.btn-sig-receipt {
--btn-bg: #2b2d33;
--btn-fg: #d7dae0;
--btn-font: ui-monospace, monospace;
--btn-size: 13px;
--btn-weight: 600;
--btn-px: 22px;
--btn-py: 12px;
--btn-w: auto;
--btn-h: auto;
--btn-bw: 0px;
--btn-line: #8b6cff;
--btn-radius: 8px;
--btn-speed: 700ms;
}
.btn-sig-receipt {
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: var(--btn-py) var(--btn-px);
font-family: var(--btn-font);
font-size: var(--btn-size);
font-weight: var(--btn-weight);
line-height: 1.2;
color: var(--btn-fg);
background: var(--btn-bg);
border: var(--btn-bw) solid var(--btn-line);
border-radius: var(--btn-radius);
box-shadow: inset 0 -5px 0 #101114, 0 4px 10px rgba(0,0,0,.35);
cursor: pointer;
text-decoration: none;
white-space: nowrap;
transition: all var(--btn-speed) ease;
margin-bottom: 58px;
}
.btn-sig-receipt:focus-visible {
outline: 2px solid var(--btn-bg);
outline-offset: 2px;
}
.btn-sig-receipt:disabled {
opacity: 0.5;
pointer-events: none;
}
.btn-sig-receipt__icon {
width: 1.15em;
height: 1.15em;
flex-shrink: 0;
}
.btn-sig-receipt::after {
content: "";
position: absolute;
left: 10px;
right: 10px;
bottom: 1px;
height: 3px;
background: #000;
border-radius: 2px;
}
.btn-sig-receipt[data-state=out] {
--out: 0;
}
.btn-sig-receipt__slot {
position: absolute;
top: 100%;
left: 14px;
right: 14px;
height: 58px;
overflow: hidden;
}
.btn-sig-receipt__paper {
display: block;
box-sizing: border-box;
height: 54px;
padding: 9px 6px;
color: #26252c;
font-size: 12px;
text-align: center;
background: #fbfaf5;
clip-path: polygon(0 0, 100% 0, 100% 92%, 90% 100%, 80% 92%, 70% 100%, 60% 92%, 50% 100%, 40% 92%, 30% 100%, 20% 92%, 10% 100%, 0 92%);
transform: translateY(calc(var(--out, -1) * 100%));
transition: transform var(--btn-speed) steps(7);
}
@media (prefers-reduced-motion: reduce) {
.btn-sig-receipt,
.btn-sig-receipt__paper {
animation: none !important;
transition: none !important;
}
}
sig-receipt.js
document.querySelectorAll(".btn-sig-receipt").forEach((el) => {
let timer = 0;
const run = () => {
el.dataset.state = "out";
window.clearTimeout(timer);
timer = window.setTimeout(() => el.removeAttribute("data-state"), 2600);
};
el.addEventListener("click", run);
return () => {
window.clearTimeout(timer);
el.removeEventListener("click", run);
};
});
sig-receipt.tsx
import { useEffect, useRef } from "react";
import type React from "react";
import "./sig-receipt.css"; // the CSS tab
function attach(el: HTMLElement) {
let timer = 0;
const run = () => {
el.dataset.state = "out";
window.clearTimeout(timer);
timer = window.setTimeout(() => el.removeAttribute("data-state"), 2600);
};
el.addEventListener("click", run);
return () => {
window.clearTimeout(timer);
el.removeEventListener("click", run);
};
}
export function BtnSigReceipt({ children = "Print bill", ...props }: React.ComponentProps<"button">) {
const ref = useRef<HTMLButtonElement>(null);
useEffect(() => attach(ref.current!), []);
return (
<button className="btn-sig-receipt" type="button" ref={ref} {...props}>
<span className="btn-sig-receipt__word">{children}</span>
<span className="btn-sig-receipt__slot" aria-hidden="true">
<span className="btn-sig-receipt__paper">{"PAID ₹499"}</span>
</span>
</button>
);
}
sig-receipt.html
<button class="btn-sig-receipt relative inline-flex items-center justify-center gap-[0.5em] [box-sizing:border-box] [padding:12px_22px] [font-family:ui-monospace,_monospace] text-[13px] font-[600] [line-height:1.2] text-[#d7dae0] bg-[#2b2d33] [border:0px_solid_#8b6cff] rounded-[8px] [box-shadow:inset_0_-5px_0_#101114,_0_4px_10px_rgba(0,0,0,.35)] cursor-pointer no-underline whitespace-nowrap [transition:all_700ms_ease] [margin-bottom:58px] focus-visible:[outline:2px_solid_#2b2d33] focus-visible:[outline-offset:2px] disabled:[opacity:0.5] disabled:[pointer-events:none] after:content-[''] after:absolute after:[left:10px] after:[right:10px] after:[bottom:1px] after:h-[3px] after:bg-[#000] after:rounded-[2px] [&[data-state=out]]:[--out:0] motion-reduce:[transition:none!important]" type="button">
<span>Print bill</span>
<span class="absolute [top:100%] [left:14px] [right:14px] h-[58px] overflow-hidden" aria-hidden="true">
<span class="[display:block] [box-sizing:border-box] h-[54px] [padding:9px_6px] text-[#26252c] text-[12px] [text-align:center] bg-[#fbfaf5] [clip-path:polygon(0_0,_100%_0,_100%_92%,_90%_100%,_80%_92%,_70%_100%,_60%_92%,_50%_100%,_40%_92%,_30%_100%,_20%_92%,_10%_100%,_0_92%)] [transform:translateY(calc(var(--out,_-1)_*_100%))] [transition:transform_700ms_steps(7)] motion-reduce:[transition:none!important]">PAID ₹499</span>
</span>
</button>
<!-- Needs the script from the JS tab. -->