Kortingscode met alle staten New
Discount code field inside an order summary: first a link, then field plus Apply. States: empty (button disabled), checking (spinner, aria-busy), valid (code as a chip with remove button, discount line and a total that counts to the new amount), invalid and expired (with date). Try-chips fill in a code. Codes are mock data in the JS; in production your server checks them. Total animation is off under prefers-reduced-motion.
- Subtotaal 3 artikelen
- Verzending
- € 4,95
- Korting
- Totaal incl. btw
Probeer
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.
<!-- Kortingscode met alle staten · NedDev · eigen werk. -->
<div class="jouw-container">
<div class="bkc"><dl class="bkc__dl"><div><dt>Subtotaal <span>3 artikelen</span></dt><dd class="bkc__sub"></dd></div><div><dt>Verzending</dt><dd>€ 4,95</dd></div><div class="bkc__disc" hidden><dt>Korting <span class="bkc__dc"></span></dt><dd class="bkc__dv"></dd></div><div class="bkc__tot"><dt>Totaal <span>incl. btw</span></dt><dd class="bkc__t" aria-live="polite"></dd></div></dl><button type="button" class="bkc__reveal" aria-expanded="false" aria-controls="bkc-box">Kortingscode toevoegen</button><div class="bkc__box" id="bkc-box" hidden><form class="bkc__form" novalidate><label class="bkc__vh" for="bkc-in">Kortingscode</label><div class="bkc__ctl"><input id="bkc-in" class="bkc__in" autocomplete="off" autocapitalize="characters" spellcheck="false" placeholder="Kortingscode" aria-describedby="bkc-msg"><button type="button" class="bkc__clr" aria-label="Veld leegmaken" hidden>×</button></div><button type="submit" class="bkc__ap" disabled>Toepassen</button></form><p class="bkc__msg" id="bkc-msg" aria-live="polite"></p><div class="bkc__chip" hidden><span class="bkc__cn"></span><button type="button" class="bkc__rm" aria-label="Kortingscode verwijderen">×</button></div></div><p class="bkc__try">Probeer <button type="button" data-c="HERFST10">HERFST10</button><button type="button" data-c="WELKOM5">WELKOM5</button><button type="button" data-c="ZOMER25">ZOMER25</button><button type="button" data-c="GRATIS">GRATIS</button></p></div>
</div>/* Kortingscode met alle staten · NedDev · eigen werk. */
.bkc{position:absolute;inset:0;padding:12px 16px;background:#fff;font-family:'Switzer',system-ui,sans-serif;color:#0a0a0a;overflow:auto;display:flex;flex-direction:column}
.bkc__vh{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.bkc__dl{margin:0 0 8px;font-size:13px}
.bkc__dl>div{display:flex;justify-content:space-between;gap:10px;padding:2px 0}
.bkc__dl dt{color:#5c5a56}
.bkc__dl dt span{font-size:11px;color:#76736d}
.bkc__dl dd{margin:0;font-variant-numeric:tabular-nums}
.bkc__disc[hidden]{display:none}
.bkc__disc dd,.bkc__disc dt{color:#1f6b38;font-weight:600}
.bkc__disc dt span{display:inline-block;margin-left:2px;padding:0 4px;border-radius:3px;background:#e3f1e7;color:#1f6b38;font:600 10px/16px 'JetBrains Mono',monospace}
.bkc__tot{margin-top:5px;padding-top:7px!important;border-top:1px solid rgba(10,10,10,.12)}
.bkc__tot dt{color:#0a0a0a;font-weight:700;font-size:14px}
.bkc__tot dd{font-weight:700;font-size:17px}
.bkc__reveal{align-self:flex-start;padding:2px 0;border:0;background:none;font:600 13px 'Switzer',system-ui,sans-serif;color:#0a0a0a;text-decoration:underline;text-underline-offset:3px;cursor:pointer;border-radius:2px}
.bkc__reveal:hover{color:#b8340a}
.bkc__reveal:focus-visible{outline:2px solid #0a0a0a;outline-offset:2px}
.bkc__box[hidden]{display:none}
.bkc__form{display:flex;gap:6px;margin:0}
.bkc__ctl{position:relative;flex:1;min-width:0}
.bkc__in{width:100%;box-sizing:border-box;height:36px;padding:0 30px 0 10px;border:1px solid rgba(10,10,10,.3);border-radius:4px;background:#fff;font:600 13.5px 'JetBrains Mono',monospace;letter-spacing:.04em;text-transform:uppercase;color:#0a0a0a;transition:border-color .15s,box-shadow .15s}
.bkc__in::placeholder{font-family:'Switzer',system-ui,sans-serif;letter-spacing:0;text-transform:none;font-weight:500;color:#76736d}
.bkc__in:hover{border-color:rgba(10,10,10,.55)}
.bkc__in:focus{outline:none;border-color:#0a0a0a;box-shadow:0 0 0 3px rgba(245,72,15,.3)}
.bkc.is-err .bkc__in{border-color:#c4231b;background:#fffafa}
.bkc.is-err .bkc__in:focus{box-shadow:0 0 0 3px rgba(196,35,27,.2)}
.bkc__clr{position:absolute;right:4px;top:50%;width:24px;height:24px;margin-top:-12px;border:0;border-radius:50%;background:none;font-size:16px;line-height:1;color:#5c5a56;cursor:pointer}
.bkc__clr:hover{background:#f4f3f1;color:#0a0a0a}
.bkc__clr:focus-visible{outline:2px solid #0a0a0a}
.bkc__clr[hidden]{display:none}
.bkc__ap{position:relative;flex:none;height:36px;padding:0 14px;border:1px solid #0a0a0a;border-radius:4px;background:#0a0a0a;color:#fff;font:600 13px 'Switzer',system-ui,sans-serif;cursor:pointer;transition:background-color .15s,color .15s,border-color .15s}
.bkc__ap:hover:not(:disabled){background:#F5480F;border-color:#F5480F;color:#0a0a0a}
.bkc__ap:active:not(:disabled){transform:translateY(1px)}
.bkc__ap:focus-visible{outline:2px solid #0a0a0a;outline-offset:2px}
.bkc__ap:disabled{background:#e9e7e3;border-color:#e9e7e3;color:#76736d;cursor:not-allowed}
.bkc__ap.is-busy{color:transparent;background:#0a0a0a;border-color:#0a0a0a;cursor:progress}
.bkc__ap.is-busy::after{content:'';position:absolute;inset:0;margin:auto;width:14px;height:14px;border:2px solid #fff;border-right-color:transparent;border-radius:50%;animation:bkc-spin .7s linear infinite}
@keyframes bkc-spin{to{transform:rotate(360deg)}}
.bkc__msg{margin:5px 0 0;font-size:12px;line-height:1.35;color:#5c5a56}
.bkc__msg:empty{display:none}
.bkc.is-err .bkc__msg{color:#c4231b}
.bkc.is-ok .bkc__msg{color:#1f6b38}
.bkc__chip{display:inline-flex;align-items:center;gap:4px;margin-top:2px;padding:3px 3px 3px 9px;border-radius:999px;background:#e3f1e7;color:#14532d;font:600 12px 'JetBrains Mono',monospace}
.bkc__chip[hidden]{display:none}
.bkc__rm{width:22px;height:22px;border:0;border-radius:50%;background:none;color:#14532d;font-size:15px;line-height:1;cursor:pointer}
.bkc__rm:hover{background:#c9e4d1}
.bkc__rm:focus-visible{outline:2px solid #14532d}
.bkc__try{margin:auto 0 0;padding-top:8px;display:flex;flex-wrap:wrap;align-items:center;gap:4px;font:500 10px 'JetBrains Mono',monospace;text-transform:uppercase;letter-spacing:.06em;color:#5c5a56}
.bkc__try button{padding:2px 6px;border:1px dashed rgba(10,10,10,.3);border-radius:3px;background:none;font:600 10.5px 'JetBrains Mono',monospace;color:#0a0a0a;cursor:pointer;transition:border-color .15s,background-color .15s}
.bkc__try button:hover{border-style:solid;border-color:#0a0a0a;background:#f4f3f1}
.bkc__try button:focus-visible{outline:2px solid #0a0a0a;outline-offset:1px}
@media (prefers-reduced-motion:reduce){.bkc *{transition:none!important}.bkc__ap.is-busy::after{animation-duration:2s}}// Kortingscode met alle staten · NedDev · eigen werk.
// root = het element waarin de HTML staat
function init(root){
var w=root.querySelector('.bkc');if(!w)return;
var form=w.querySelector('.bkc__form'),inp=w.querySelector('.bkc__in'),ap=w.querySelector('.bkc__ap'),clr=w.querySelector('.bkc__clr'),msg=w.querySelector('.bkc__msg'),chip=w.querySelector('.bkc__chip'),cn=w.querySelector('.bkc__cn'),box=w.querySelector('.bkc__box'),rev=w.querySelector('.bkc__reveal'),disc=w.querySelector('.bkc__disc'),tEl=w.querySelector('.bkc__t');
var SUB=89,SHIP=4.95,shown=SUB+SHIP,raf=0;
/* nep-codes: in productie valideert je server de code */
var CODES={HERFST10:{type:'pct',v:10,until:'2026-11-30'},WELKOM5:{type:'eur',v:5,until:'2027-12-31'},ZOMER25:{type:'pct',v:25,until:'2026-08-31'}};
var MK=['jan','feb','mrt','apr','mei','jun','jul','aug','sep','okt','nov','dec'];
function eur(n){return '€ '+n.toLocaleString('nl-NL',{minimumFractionDigits:2,maximumFractionDigits:2})}
w.querySelector('.bkc__sub').textContent=eur(SUB);
function setTotal(to){cancelAnimationFrame(raf);if(matchMedia('(prefers-reduced-motion:reduce)').matches){shown=to;tEl.textContent=eur(to);return}var from=shown,t0=performance.now();(function step(t){var k=Math.min(1,(t-t0)/450),e=1-Math.pow(1-k,3);shown=from+(to-from)*e;tEl.textContent=eur(Math.round(shown*100)/100);if(k<1)raf=requestAnimationFrame(step)})(t0)}
function state(s,t){w.classList.toggle('is-err',s==='err');w.classList.toggle('is-ok',s==='ok');msg.textContent=t;if(s==='err')inp.setAttribute('aria-invalid','true');else inp.removeAttribute('aria-invalid')}
function fmt(iso){var p=iso.split('-');return +p[2]+' '+MK[+p[1]-1]+' '+p[0]}
function sync(){ap.disabled=!inp.value.trim()||ap.classList.contains('is-busy');clr.hidden=!inp.value}
function applied(code,c){var amt=c.type==='pct'?Math.round(SUB*c.v)/100:c.v;disc.hidden=false;w.querySelector('.bkc__dc').textContent=code;w.querySelector('.bkc__dv').textContent='−'+eur(amt);
cn.textContent=code+(c.type==='pct'?' · '+c.v+'%':' · '+eur(c.v));chip.hidden=false;form.hidden=true;state('ok','Je bespaart '+eur(amt)+'.');setTotal(SUB+SHIP-amt);chip.querySelector('.bkc__rm').focus()}
function remove(){disc.hidden=true;chip.hidden=true;form.hidden=false;inp.value='';state('','');sync();setTotal(SUB+SHIP);inp.focus()}
rev.addEventListener('click',function(){var o=box.hidden;box.hidden=!o;rev.setAttribute('aria-expanded',o);if(o)inp.focus()});
inp.addEventListener('input',function(){if(w.classList.contains('is-err'))state('','');sync()});
clr.addEventListener('click',function(){inp.value='';state('','');sync();inp.focus()});
chip.querySelector('.bkc__rm').addEventListener('click',remove);
form.addEventListener('submit',function(e){e.preventDefault();var code=inp.value.trim().toUpperCase().replace(/\s+/g,'');if(!code)return;
ap.classList.add('is-busy');ap.disabled=true;inp.setAttribute('aria-busy','true');state('','Code controleren');
setTimeout(function(){ap.classList.remove('is-busy');inp.removeAttribute('aria-busy');sync();var c=CODES[code],today=new Date().toISOString().slice(0,10);
if(!c){state('err','De code '+code+' kennen we niet. Controleer de spelling.');inp.select();return}
if(c.until<today){state('err',code+' was geldig tot '+fmt(c.until)+' en is verlopen.');inp.select();return}
applied(code,c)},650)});
w.querySelector('.bkc__try').addEventListener('click',function(e){var b=e.target.closest('button[data-c]');if(!b)return;if(!chip.hidden)remove();box.hidden=false;rev.setAttribute('aria-expanded','true');inp.value=b.dataset.c;state('','');sync();inp.focus()});
tEl.textContent=eur(shown);box.hidden=false;rev.setAttribute('aria-expanded','true');inp.value='ZOMER25';sync();state('err','ZOMER25 was geldig tot '+fmt(CODES.ZOMER25.until)+' en is verlopen.');
}
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 →