Credit Pack Grid
A copy-paste pricing tables component in pure HTML, CSS & vanilla JS. Zero dependencies, framework-agnostic, MIT-licensed.
Pricing TablesHTMLJavaScriptCSSany framework
Copy into your project
HTML
<!-- Credit Pack Grid — selecting a pack pops the card and flags best value -->
<div class="nuda-pr2-credit-packs" role="radiogroup" aria-label="Credit pack">
<button class="nuda-pr2-credit-packs__pack" type="button" role="radio" aria-checked="false">
<span class="nuda-pr2-credit-packs__amount">500</span>
<span class="nuda-pr2-credit-packs__price">$5</span>
</button>
<button class="nuda-pr2-credit-packs__pack is-selected" type="button" role="radio" aria-checked="true">
<span class="nuda-pr2-credit-packs__flag">Best value</span>
<span class="nuda-pr2-credit-packs__amount">2,000</span>
<span class="nuda-pr2-credit-packs__price">$15</span>
</button>
<button class="nuda-pr2-credit-packs__pack" type="button" role="radio" aria-checked="false">
<span class="nuda-pr2-credit-packs__amount">5,000</span>
<span class="nuda-pr2-credit-packs__price">$32</span>
</button>
</div>JavaScript
/* Credit Pack Grid — click a pack to select it (radio behavior). */
(function () {
var group = document.querySelector('.nuda-pr2-credit-packs');
if (!group) return;
var packs = group.querySelectorAll('.nuda-pr2-credit-packs__pack');
packs.forEach(function (p) {
p.addEventListener('click', function () {
packs.forEach(function (x) {
x.classList.remove('is-selected', 'is-picked');
x.setAttribute('aria-checked', 'false');
});
p.classList.add('is-selected', 'is-picked');
p.setAttribute('aria-checked', 'true');
setTimeout(function () { p.classList.remove('is-picked'); }, 400);
});
});
})();CSS
.nuda-pr2-credit-packs {
display: grid;
grid-template-columns: repeat(3,1fr);
gap: 6px;
width: 220px;
}
.nuda-pr2-credit-packs__pack {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 2px;
min-height: 52px;
padding: 8px 4px;
background: rgba(255,255,255,.03);
border: 1px solid rgba(255,255,255,.08);
border-radius: 8px;
color: #fafafa;
cursor: pointer;
transition: transform .2s,border-color .25s,box-shadow .25s;
}
.nuda-pr2-credit-packs__pack:hover {
transform: translateY(-2px);
border-color: rgba(228,255,84,.3);
}
.nuda-pr2-credit-packs__pack:focus-visible {
outline: 2px solid #e4ff54;
outline-offset: 2px;
}
.nuda-pr2-credit-packs__pack.is-selected {
border-color: #e4ff54;
box-shadow: 0 0 0 1px rgba(228,255,84,.4),0 8px 20px -6px rgba(228,255,84,.3);
}
.nuda-pr2-credit-packs__pack.is-selected.is-picked {
animation: nuda-pr2-credit-packs-pop .35s cubic-bezier(.34,1.56,.64,1);
}
.nuda-pr2-credit-packs__flag {
position: absolute;
top: -8px;
left: 50%;
transform: translateX(-50%);
padding: 1px 6px;
background: #e4ff54;
color: #09090b;
font: 800 7px ui-sans-serif,system-ui;
text-transform: uppercase;
letter-spacing: .04em;
border-radius: 999px;
white-space: nowrap;
}
.nuda-pr2-credit-packs__amount {
font: 800 13px ui-sans-serif,system-ui;
font-variant-numeric: tabular-nums;
}
.nuda-pr2-credit-packs__price {
font: 600 9px ui-sans-serif,system-ui;
color: #a1a1aa;
}
@keyframes nuda-pr2-credit-packs-pop {
0% {
transform: scale(.92);
}
50% {
transform: scale(1.05);
}
100% {
transform: scale(1);
}
}
@media (prefers-reduced-motion:reduce) {
.nuda-pr2-credit-packs__pack {
transition: none;
}
.nuda-pr2-credit-packs__pack.is-selected.is-picked {
animation: none !important;
}
}
How to use Credit Pack Grid
Paste the HTML where you need it and the CSS into a global stylesheet (or a <style> tag). Every class is prefixed nuda- so it never collides with Tailwind or your own styles. Tweak the CSS custom properties to match your design system.
Works in React, Vue, Svelte, Astro, Next.js, Nuxt, Laravel Blade, Django, Rails — or a single .html file. No npm install, no build step.