Subway Token
Aged brass subway token with a curved arc sweep that traces a clock-like ring around the inscription on click. The arc is an SVG path so the curve stays smooth at every angle.
Subway Token the 34th of 43 designs in the 43 CSS Button Designs collection. The design pairs CSS styling with a small amount of JavaScript for interactivity. Copy the HTML, CSS and JavaScript panels below into your project — the JS is self-contained, has zero dependencies, and is safe to drop into any framework (React, Vue, Svelte, plain HTML). The design honours prefers-reduced-motion and uses real semantic markup, so it ships accessibility-ready out of the box.
Live preview
The code
<button class="btn-token">
<svg class="btn-token-arc" viewBox="0 0 100 100" aria-hidden="true">
<circle cx="50" cy="50" r="42" fill="none" stroke="rgba(42,29,14,0.18)" stroke-width="3" />
<circle
class="btn-token-arc-spin"
cx="50"
cy="50"
r="42"
fill="none"
stroke="#2a1d0e"
stroke-width="3"
stroke-linecap="round"
pathLength="100"
stroke-dasharray="22 100"
/>
</svg>
<span class="btn-token-text">PROCESS</span>
</button> .btn-token {
position: relative;
width: 124px; height: 124px;
border: none; border-radius: 50%;
background:
radial-gradient(circle at 35% 30%, #e8c890 0%, #c9a15e 50%, #6a4520 100%);
color: #2a1d0e;
font-family: ui-serif, Georgia, serif;
font-size: 11px; font-weight: 800;
letter-spacing: 0.22em;
cursor: pointer;
display: grid; place-items: center;
box-shadow:
inset 0 -3px 6px rgba(0,0,0,0.4),
inset 0 3px 4px rgba(255,232,180,0.6),
0 6px 14px rgba(0,0,0,0.35);
transition: transform 0.18s ease;
}
.btn-token-arc {
position: absolute;
inset: 8px;
width: calc(100% - 16px); height: calc(100% - 16px);
pointer-events: none;
}
.btn-token-arc-spin {
transform-origin: 50% 50%;
transform: rotate(-90deg);
transition: transform 1.4s cubic-bezier(.3,1,.3,1);
}
.btn-token-text {
position: relative; z-index: 1;
text-shadow: 0 1px 0 rgba(255,232,180,0.4);
}
.btn-token.is-processing .btn-token-arc-spin {
transform: rotate(270deg);
}
.btn-token:hover { transform: scale(1.04); } document.querySelectorAll('.btn-token').forEach(function(btn) {
btn.addEventListener('click', function() {
if (btn.classList.contains('is-processing')) return;
btn.classList.add('is-processing');
setTimeout(function() { btn.classList.remove('is-processing'); }, 1400);
});
});