/Click feedback
Click feedback • CSS
Next Dot Fill Button
A bordered pill whose leading dot expands into a solid fill while the label swaps for an arrow cue.
Installation
Requires lucide-react for its icons. The shadcn CLI installs it for you; copying the code by hand means installing it yourself.
Terminal
npx shadcn@latest add https://microkit.co/r/next-dot-fill-button.jsonCode
TypeScript component
1import "./styles.css";23import { ArrowRight } from "lucide-react";45export function NextDotFillButton() {6return (7<button type="button" className="next-dot-fill-button">8<span className="next-dot-fill-button__fill" aria-hidden="true" />9<span className="next-dot-fill-button__label">Next</span>10<span className="next-dot-fill-button__reveal" aria-hidden="true">11Next12<ArrowRight size={19} strokeWidth={2.4} />13</span>14</button>15);16}
CSS
1.next-dot-fill-button,2.next-dot-fill-button * {3box-sizing: border-box;4}5.next-dot-fill-button {6appearance: none;7position: relative;8display: inline-flex;9width: min(132px, calc(100vw - 40px));10height: 50px;11align-items: center;12justify-content: center;13overflow: hidden;14border: 1px solid #d7dbe2;15border-radius: 999px;16background: #fff;17padding: 0;18color: #0a0a0a;19font-family: Arial, Helvetica, sans-serif;20font-size: 16px;21font-weight: 500;22letter-spacing: -.02em;23line-height: 1;24cursor: pointer;25}26.next-dot-fill-button__fill {27position: absolute;28left: 26px;29top: calc(50% - 4.5px);30z-index: 1;31width: 9px;32height: 9px;33border-radius: 50%;34background: #0a0a0a;35transition: transform .5s cubic-bezier(.16, 1, .3, 1);36}37.next-dot-fill-button__label {38position: relative;39z-index: 0;40transform: translateX(5px);41transition: transform .35s cubic-bezier(.16, 1, .3, 1), opacity .3s ease;42}43.next-dot-fill-button__reveal {44position: absolute;45inset: 0;46z-index: 2;47display: inline-flex;48align-items: center;49justify-content: center;50gap: 8px;51color: #fafafa;52transform: translateX(46px);53opacity: 0;54transition: transform .35s cubic-bezier(.16, 1, .3, 1), opacity .3s ease;55}56.next-dot-fill-button__reveal svg {57flex-shrink: 0;58}59.next-dot-fill-button:hover .next-dot-fill-button__fill,60.next-dot-fill-button:focus-visible .next-dot-fill-button__fill {61transform: scale(28);62}63.next-dot-fill-button:hover .next-dot-fill-button__label,64.next-dot-fill-button:focus-visible .next-dot-fill-button__label {65transform: translateX(46px);66opacity: 0;67}68.next-dot-fill-button:hover .next-dot-fill-button__reveal,69.next-dot-fill-button:focus-visible .next-dot-fill-button__reveal {70transform: translateX(0);71opacity: 1;72}73.next-dot-fill-button:focus-visible {74outline: 2px solid #f97316;75outline-offset: 4px;76}77@media (prefers-reduced-motion: reduce) {78.next-dot-fill-button__fill,79.next-dot-fill-button__label,80.next-dot-fill-button__reveal {81transition: none;82}83}