Betaalmethode als radiokaarten New
Payment choice for a Dutch web shop: iDEAL (with bank choice), credit card (number grouped in fours with Luhn check, expiry, CVC), Bancontact and pay later. The chosen card expands via grid-template-rows 0fr to 1fr and :has(:checked); closed panels are inert so Tab skips them. Without :has() JS sets a class. States: per-method error, redirecting (loading) and paid. Text labels instead of brand logos; in production you wire this to your PSP (e.g. Mollie or Adyen).
How to use it
- Paste the HTML where the forms & inputs should appear.
- Add the CSS to your stylesheet. All classes are prefixed, so nothing clashes with your own styles.
- Add the JavaScript and call init() with the element that contains the HTML.
<!-- Betaalmethode als radiokaarten · NedDev · eigen werk. -->
<div class="jouw-container">
<form class="bbm" novalidate><fieldset class="bbm__fs"><legend class="bbm__lg">Hoe wil je betalen?</legend><label class="bbm__opt"><input type="radio" name="bbm-m" value="ideal" checked><span class="bbm__row"><span class="bbm__nm">iDEAL</span><span class="bbm__sub">direct via je eigen bank</span><span class="bbm__tag">iDEAL</span></span></label><div class="bbm__more" data-m="ideal"><div class="bbm__mi"><label class="bbm__f bbm__f--in">Je bank<select class="bbm__bank" aria-describedby="bbm-e-ideal"><option value="">Kies je bank</option><option>ABN AMRO</option><option>ASN Bank</option><option>bunq</option><option>ING</option><option>Knab</option><option>Rabobank</option><option>Revolut</option><option>SNS</option><option>Triodos Bank</option></select></label><p class="bbm__e" id="bbm-e-ideal"></p></div></div><label class="bbm__opt"><input type="radio" name="bbm-m" value="card"><span class="bbm__row"><span class="bbm__nm">Creditcard</span><span class="bbm__sub">Visa, Mastercard, Amex</span><span class="bbm__tag">KAART</span></span></label><div class="bbm__more" data-m="card"><div class="bbm__mi"><div class="bbm__cc"><label class="bbm__f bbm__f--n">Kaartnummer<input class="bbm__num" inputmode="numeric" autocomplete="cc-number" placeholder="1234 5678 9012 3456" maxlength="23" aria-describedby="bbm-e-card"></label><label class="bbm__f">Geldig tot<input class="bbm__exp" inputmode="numeric" autocomplete="cc-exp" placeholder="MM/JJ" maxlength="5"></label><label class="bbm__f">CVC<input class="bbm__cvc" inputmode="numeric" autocomplete="cc-csc" placeholder="123" maxlength="4"></label></div><p class="bbm__e" id="bbm-e-card"></p></div></div><label class="bbm__opt"><input type="radio" name="bbm-m" value="bc"><span class="bbm__row"><span class="bbm__nm">Bancontact</span><span class="bbm__sub">voor Belgische rekeningen</span><span class="bbm__tag">BC</span></span></label><div class="bbm__more" data-m="bc"><div class="bbm__mi"><p class="bbm__p">Je rondt de betaling af in de Bancontact-app of met je kaart en kaartlezer.</p></div></div><label class="bbm__opt"><input type="radio" name="bbm-m" value="later"><span class="bbm__row"><span class="bbm__nm">Achteraf betalen</span><span class="bbm__sub">binnen 30 dagen, geen extra kosten</span><span class="bbm__tag">30 DGN</span></span></label><div class="bbm__more" data-m="later"><div class="bbm__mi"><label class="bbm__ck"><input type="checkbox" class="bbm__agree" aria-describedby="bbm-e-later"> Ik ga akkoord met een korte kredietcheck en de voorwaarden.</label><p class="bbm__e" id="bbm-e-later"></p></div></div></fieldset><button type="submit" class="bbm__go">Betaal € 54,85</button><p class="bbm__st" role="status" aria-live="polite"></p></form>
</div>/* Betaalmethode als radiokaarten · NedDev · eigen werk. */
.bbm{position:absolute;inset:0;margin:0;padding:8px 12px;background:#fff;font-family:'Switzer',system-ui,sans-serif;color:#0a0a0a;overflow:auto;display:flex;flex-direction:column;gap:7px}
.bbm__fs{margin:0;padding:0;border:0;min-width:0;display:flex;flex-direction:column}
.bbm__lg{padding:0;margin-bottom:5px;font-size:13.5px;font-weight:700}
.bbm__opt{position:relative;display:block;cursor:pointer}
.bbm__opt input{position:absolute;z-index:2;left:11px;top:50%;width:15px;height:15px;margin:-7.5px 0 0;accent-color:#0a0a0a;cursor:pointer}
.bbm__row{display:grid;grid-template-columns:auto 1fr auto;align-items:center;gap:8px;padding:6px 10px 6px 34px;border:1px solid rgba(10,10,10,.18);margin-top:-1px;transition:background-color .15s,border-color .15s}
.bbm__opt:first-of-type .bbm__row{border-radius:6px 6px 0 0;margin-top:0}
.bbm__fs>.bbm__more:last-child .bbm__mi{border-radius:0 0 6px 6px}
.bbm__fs>.bbm__opt:nth-last-of-type(1) .bbm__row{border-radius:0 0 6px 6px}
.bbm__opt:hover .bbm__row{background:#fafaf9}
.bbm__opt input:focus-visible{outline:2px solid #0a0a0a;outline-offset:2px}
.bbm__opt:has(input:checked) .bbm__row,.bbm__opt.is-on .bbm__row{position:relative;z-index:1;border-color:#0a0a0a;box-shadow:inset 0 0 0 1px #0a0a0a;border-radius:0;background:#fff}
.bbm__opt:first-of-type:has(input:checked) .bbm__row{border-radius:6px 6px 0 0}
.bbm__nm{font-size:13px;font-weight:700}
.bbm__sub{font-size:11px;color:#5c5a56;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.bbm__tag{padding:2px 5px;border:1px solid rgba(10,10,10,.25);border-radius:3px;font:600 9px 'JetBrains Mono',monospace;letter-spacing:.04em;color:#0a0a0a;background:#f4f3f1}
.bbm__more{display:grid;grid-template-rows:0fr;transition:grid-template-rows .22s cubic-bezier(.2,.7,.2,1)}
.bbm__opt:has(input:checked)+.bbm__more,.bbm__more.is-on{grid-template-rows:1fr}
.bbm__mi{min-height:0;overflow:hidden;padding:0 10px 0 34px;border-left:1px solid #0a0a0a;border-right:1px solid #0a0a0a;background:#fbfaf8}
.bbm__more.is-on .bbm__mi,.bbm__opt:has(input:checked)+.bbm__more .bbm__mi{padding-top:6px;padding-bottom:7px;border-bottom:1px solid #0a0a0a;box-shadow:inset 1px 0 0 #0a0a0a,inset -1px 0 0 #0a0a0a}
.bbm__more:not(.is-on) .bbm__mi{border-color:transparent}
.bbm__f{display:block;font-size:10.5px;font-weight:600;color:#5c5a56}
.bbm__f select,.bbm__f input{display:block;width:100%;box-sizing:border-box;height:30px;margin-top:2px;padding:0 8px;border:1px solid rgba(10,10,10,.3);border-radius:4px;background:#fff;font:500 13px 'Switzer',system-ui,sans-serif;color:#0a0a0a;font-variant-numeric:tabular-nums;transition:border-color .15s,box-shadow .15s}
.bbm__f select:focus,.bbm__f input:focus{outline:none;border-color:#0a0a0a;box-shadow:0 0 0 3px rgba(245,72,15,.3)}
.bbm__f [aria-invalid="true"]{border-color:#c4231b}
.bbm__f--in{display:flex;align-items:center;gap:10px}.bbm__f--in select{flex:1;margin-top:0}
.bbm__cc{display:grid;grid-template-columns:1fr 62px 50px;gap:6px}
.bbm__e{margin:4px 0 0;font-size:11px;color:#c4231b}
.bbm__e:empty{display:none}
.bbm__p{margin:0;font-size:11.5px;line-height:1.4;color:#3d3b37}
.bbm__ck{display:flex;gap:7px;align-items:flex-start;font-size:11.5px;line-height:1.35;cursor:pointer}
.bbm__ck input{margin:1px 0 0;accent-color:#0a0a0a}
.bbm__ck input:focus-visible{outline:2px solid #0a0a0a;outline-offset:2px}
.bbm__go{flex:none;height:36px;border:0;border-radius:4px;background:#0a0a0a;color:#fff;font:600 13.5px 'Switzer',system-ui,sans-serif;cursor:pointer;transition:background-color .15s,color .15s}
.bbm__go:hover:not(:disabled){background:#F5480F;color:#0a0a0a}
.bbm__go:active:not(:disabled){transform:translateY(1px)}
.bbm__go:focus-visible{outline:2px solid #0a0a0a;outline-offset:2px}
.bbm__go:disabled{background:#3d3b37;cursor:progress}
.bbm__go.is-paid{background:#1f7a3d;color:#fff}
.bbm__st{margin:0;font-size:11.5px;color:#5c5a56;min-height:0}
.bbm__st:empty{display:none}
@media (prefers-reduced-motion:reduce){.bbm *{transition:none!important}}// Betaalmethode als radiokaarten · NedDev · eigen werk.
// root = het element waarin de HTML staat
function init(root){
var f=root.querySelector('.bbm');if(!f)return;
var go=f.querySelector('.bbm__go'),st=f.querySelector('.bbm__st'),num=f.querySelector('.bbm__num'),exp=f.querySelector('.bbm__exp'),cvc=f.querySelector('.bbm__cvc');
function cur(){return f.querySelector('input[name="bbm-m"]:checked').value}
function sync(){var m=cur();f.querySelectorAll('.bbm__more').forEach(function(p){var on=p.dataset.m===m;p.classList.toggle('is-on',on);if(on)p.removeAttribute('inert');else p.setAttribute('inert','')});f.querySelectorAll('.bbm__opt').forEach(function(o){o.classList.toggle('is-on',o.querySelector('input').checked)});clear();go.classList.remove('is-paid');go.disabled=false;go.innerHTML='Betaal € 54,85';st.textContent=''}
function clear(){f.querySelectorAll('.bbm__e').forEach(function(e){e.textContent=''});f.querySelectorAll('[aria-invalid]').forEach(function(e){e.removeAttribute('aria-invalid')})}
function fail(m,el,txt){var e=f.querySelector('#bbm-e-'+m);e.textContent=txt;if(el){el.setAttribute('aria-invalid','true');el.focus()}return false}
function luhn(n){var s=0,alt=false;for(var i=n.length-1;i>=0;i--){var d=+n[i];if(alt){d*=2;if(d>9)d-=9}s+=d;alt=!alt}return s%10===0}
function valid(){clear();var m=cur();
if(m==='ideal'){var b=f.querySelector('.bbm__bank');return b.value?true:fail(m,b,'Kies je bank om verder te gaan.')}
if(m==='card'){var n=num.value.replace(/\s/g,'');if(n.length<13||!luhn(n))return fail(m,num,'Dit kaartnummer klopt niet. Controleer de cijfers.');
var p=exp.value.split('/'),mm=+p[0],yy=+p[1];var now=new Date(),cy=now.getFullYear()%100,cm=now.getMonth()+1;if(!(mm>=1&&mm<=12)||isNaN(yy)||yy<cy||(yy===cy&&mm<cm))return fail(m,exp,'Deze kaart is verlopen of de datum klopt niet (MM/JJ).');
if(!/^\d{3,4}$/.test(cvc.value))return fail(m,cvc,'Vul de 3 cijfers op de achterkant in.');return true}
if(m==='later'){var a=f.querySelector('.bbm__agree');return a.checked?true:fail(m,a,'Vink aan dat je akkoord gaat met de kredietcheck.')}
return true}
num.addEventListener('input',function(){var d=num.value.replace(/\D/g,'').slice(0,19);num.value=d.replace(/(\d{4})(?=\d)/g,'$1 ')});
exp.addEventListener('input',function(e){var d=exp.value.replace(/\D/g,'').slice(0,4);exp.value=d.length>2?d.slice(0,2)+'/'+d.slice(2):d});
cvc.addEventListener('input',function(){cvc.value=cvc.value.replace(/\D/g,'').slice(0,4)});
f.addEventListener('change',function(e){if(e.target.name==='bbm-m')sync();else if(e.target.getAttribute('aria-invalid'))valid()});
f.addEventListener('submit',function(e){e.preventDefault();if(go.classList.contains('is-paid'))return;if(!valid())return;var m=cur(),to={ideal:'je bank',card:'3D Secure van je kaart',bc:'Bancontact',later:'de achteraf-betaalpartner'}[m];
go.disabled=true;go.textContent='Doorsturen naar '+to;st.textContent='';setTimeout(function(){go.disabled=false;go.classList.add('is-paid');go.textContent='Betaald';st.textContent='Betaling van € 54,85 ontvangen. Bestelnummer HA-108233.'},900)});
sync();
}
init(document.querySelector('.jouw-container'));
More forms & inputs
Seen something you like?
Add it to your selection and send it over. We build your site around it, in your brand.
Get in touch →