Abonnement opzeggen Nieuw
Opzeggen van een abonnement zoals het in Nederland hoort: de opzegknop staat even zichtbaar als wijzigen, daarna één bevestigingsscherm met einddatum en laatste incasso, een reden die echt optioneel is, geen behoudtrucs, en een bevestiging met de tekst van de bevestigingsmail en een referentienummer. Laden en fout (via de demoschakelaar) zijn te zien. Wisselt scherm met View Transitions; zonder support of bij reduced motion direct.
Mijn abonnement
Flex-abonnement, Sportschool De Kade Utrecht
Opzegging bevestigen
Je Flex-abonnement loopt door tot en met (opzegtermijn 1 maand). De laatste incasso is .
Opzegging ontvangen
- Einddatum
- Ontvangen op
- Referentie
Bevestigingsmail naar s.devries@voorbeeld.nl
Onderwerp: Bevestiging van je opzegging
Hoi Sanne, we hebben je opzegging van het Flex-abonnement ontvangen op . Je kunt nog sporten tot en met . De laatste incasso is ; daarna schrijven we niets meer af. Bewaar deze mail als bewijs. Referentie: .
Zo gebruik je het
- Plak de HTML op de plek waar het onderdeel moet komen.
- Zet de CSS in je stylesheet. Alle klassen hebben een eigen voorvoegsel, dus niets botst met je eigen opmaak.
- Voeg de JavaScript toe en roep init() aan met het element waar de HTML in staat.
<!-- Abonnement opzeggen · NedDev · eigen werk. -->
<div class="jouw-container">
<div class="ozf">
<div class="ozf__v" data-v="1">
<h3 class="ozf__h" tabindex="-1">Mijn abonnement</h3>
<div class="ozf__sub">
<p class="ozf__name">Flex-abonnement, Sportschool De Kade Utrecht</p>
<p class="ozf__meta">€ 34,95 per maand, maandelijks opzegbaar. Volgende incasso op 1 november.</p>
<div class="ozf__row">
<button type="button" class="ozf__btn" data-go="wijzig">Abonnement wijzigen</button>
<button type="button" class="ozf__btn" data-go="2">Abonnement opzeggen</button>
</div>
<p class="ozf__note" aria-live="polite"></p>
</div>
</div>
<div class="ozf__v" data-v="2" hidden>
<h3 class="ozf__h" tabindex="-1">Opzegging bevestigen</h3>
<p class="ozf__p">Je Flex-abonnement loopt door tot en met <strong class="ozf__end"></strong> (opzegtermijn 1 maand). De laatste incasso is <span class="ozf__last"></span>.</p>
<fieldset class="ozf__fs">
<legend>Waarom stop je? <span>(optioneel, je mag dit overslaan)</span></legend>
<label><input type="radio" name="ozf-r" value="verhuizing"> Ik ga verhuizen</label>
<label><input type="radio" name="ozf-r" value="prijs"> Te duur</label>
<label><input type="radio" name="ozf-r" value="weinig"> Ik sport te weinig</label>
<label><input type="radio" name="ozf-r" value="anders"> Anders</label>
<textarea class="ozf__ta" rows="2" aria-label="Toelichting (optioneel)" placeholder="Toelichting (optioneel)" hidden></textarea>
</fieldset>
<p class="ozf__err" role="alert"></p>
<div class="ozf__row">
<button type="button" class="ozf__btn ozf__btn--main" data-go="3">Opzegging bevestigen</button>
<button type="button" class="ozf__btn" data-go="1">Toch niet</button>
</div>
<label class="ozf__demo"><input type="checkbox"> Demo: simuleer een storing</label>
</div>
<div class="ozf__v" data-v="3" hidden>
<h3 class="ozf__h" tabindex="-1">Opzegging ontvangen</h3>
<dl class="ozf__dl">
<dt>Einddatum</dt><dd class="ozf__end"></dd>
<dt>Ontvangen op</dt><dd class="ozf__got"></dd>
<dt>Referentie</dt><dd class="ozf__ref"></dd>
</dl>
<div class="ozf__mail">
<p class="ozf__mh">Bevestigingsmail naar s.devries@voorbeeld.nl</p>
<p><strong>Onderwerp:</strong> Bevestiging van je opzegging</p>
<p>Hoi Sanne, we hebben je opzegging van het Flex-abonnement ontvangen op <span class="ozf__got"></span>. Je kunt nog sporten tot en met <span class="ozf__end"></span>. De laatste incasso is <span class="ozf__last"></span>; daarna schrijven we niets meer af. Bewaar deze mail als bewijs. Referentie: <span class="ozf__ref"></span>.</p>
</div>
<div class="ozf__row"><button type="button" class="ozf__btn" data-go="undo">Opzegging intrekken</button></div>
</div>
</div>
</div>/* Abonnement opzeggen · NedDev · eigen werk. */
.ozf{--ink:#0a0a0a;--pop:#F5480F;--pd:#b83a0b;--mut:#5b5b5b;--line:rgba(10,10,10,.12);position:absolute;inset:0;overflow:auto;padding:12px 14px;font-family:'Switzer',system-ui,sans-serif;font-size:12.5px;line-height:1.45;color:var(--ink);background:#fff;scrollbar-width:thin;text-align:left}
.ozf *,.ozf *::before,.ozf *::after{box-sizing:border-box}
.ozf__v[hidden]{display:none}
.ozf__h{margin:0 0 8px;font-size:15px;font-weight:600;letter-spacing:-.01em}
.ozf__h:focus{outline:none}
.ozf__sub{padding:12px;border:1px solid var(--line);border-radius:4px;background:#f4f3f1}
.ozf__name{margin:0;font-weight:600;font-size:13px}
.ozf__meta{margin:2px 0 10px;color:var(--mut)}
.ozf__note{margin:8px 0 0;font-size:12px}
.ozf__note:empty{display:none}
.ozf__p{margin:0 0 8px}
.ozf__row{display:flex;flex-wrap:wrap;gap:6px}
.ozf__btn{height:32px;padding:0 12px;border:1px solid var(--ink);border-radius:4px;background:#fff;color:var(--ink);font:500 12.5px/1 'Switzer',system-ui,sans-serif;cursor:pointer;transition:background-color .15s,color .15s}
.ozf__btn:hover{background:var(--ink);color:#fff}
.ozf__btn:active{transform:translateY(1px)}
.ozf__btn--main{background:var(--ink);color:#fff}
.ozf__btn--main:hover{background:#2a2a2a}
.ozf__btn[aria-busy="true"]{opacity:.6;cursor:progress}
.ozf button:focus-visible,.ozf input:focus-visible,.ozf textarea:focus-visible{outline:2px solid var(--pop);outline-offset:2px}
.ozf__fs{margin:0 0 8px;padding:8px 10px;border:1px solid var(--line);border-radius:4px;display:flex;flex-wrap:wrap;gap:4px 14px}
.ozf__fs legend{padding:0 4px;font-weight:600;font-size:12px}
.ozf__fs legend span{font-weight:400;color:var(--mut)}
.ozf__fs label{display:inline-flex;align-items:center;gap:5px;cursor:pointer}
.ozf__fs input{accent-color:var(--ink);margin:0}
.ozf__ta{flex-basis:100%;width:100%;padding:6px 8px;border:1px solid rgba(10,10,10,.3);border-radius:4px;font:500 12.5px/1.35 'Switzer',system-ui,sans-serif;resize:vertical}
@supports (field-sizing:content){.ozf__ta{field-sizing:content;min-height:44px;max-height:110px}}
.ozf__ta[hidden]{display:none}
.ozf__err{margin:0 0 8px;color:var(--pd);font-weight:500}
.ozf__err:empty{display:none}
.ozf__demo{display:flex;align-items:center;gap:6px;margin-top:10px;padding-top:8px;border-top:1px dashed var(--line);font-size:11.5px;color:var(--mut);cursor:pointer}
.ozf__demo input{accent-color:var(--ink);margin:0}
.ozf__dl{display:grid;grid-template-columns:auto 1fr;gap:2px 12px;margin:0 0 10px}
.ozf__dl dt{color:var(--mut)}
.ozf__dl dd{margin:0;font-weight:600}
.ozf__mail{margin:0 0 10px;padding:10px 12px;border:1px solid var(--line);border-radius:4px;background:#f4f3f1;font-size:12px}
.ozf__mail p{margin:0 0 4px}
.ozf__mh{color:var(--mut)}
@media (prefers-reduced-motion:reduce){.ozf *{transition:none!important}}// Abonnement opzeggen · NedDev · eigen werk.
// root = het element waarin de HTML staat
function init(root){
const w = root.querySelector('.ozf'); if (!w) return;
const reduce = matchMedia('(prefers-reduced-motion: reduce)').matches;
const fD = new Intl.DateTimeFormat('nl-NL', { day: 'numeric', month: 'long', year: 'numeric' });
const fT = new Intl.DateTimeFormat('nl-NL', { weekday: 'short', day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' });
const eur = new Intl.NumberFormat('nl-NL', { style: 'currency', currency: 'EUR' });
const ta = w.querySelector('.ozf__ta'), err = w.querySelector('.ozf__err'), demo = w.querySelector('.ozf__demo input');
const note = w.querySelector('.ozf__note');
let cancelled = false;
function dates() {
const now = new Date(), end = new Date(now); end.setMonth(end.getMonth() + 1);
const first = new Date(end.getFullYear(), end.getMonth(), 1);
const dim = new Date(end.getFullYear(), end.getMonth() + 1, 0).getDate();
const amt = Math.round(34.95 * end.getDate() / dim * 100) / 100;
return { now, end, last: 'op ' + fD.format(first) + ' (' + eur.format(amt) + ', naar rato)' };
}
const set = (sel, t) => w.querySelectorAll(sel).forEach(e => { e.textContent = t; });
function go(n) {
const swap = () => {
w.querySelectorAll('.ozf__v').forEach(v => { v.hidden = v.dataset.v !== String(n); });
w.scrollTop = 0;
w.querySelector('.ozf__v[data-v="' + n + '"] .ozf__h').focus();
};
if (document.startViewTransition && !reduce) document.startViewTransition(swap); else swap();
}
const d0 = dates(); set('.ozf__end', fD.format(d0.end)); set('.ozf__last', d0.last);
w.addEventListener('change', e => {
if (e.target.name === 'ozf-r') { ta.hidden = e.target.value !== 'anders'; if (!ta.hidden) ta.focus(); }
});
w.addEventListener('click', e => {
const b = e.target.closest('[data-go]'); if (!b) return;
const g = b.dataset.go;
if (g === 'wijzig') { note.textContent = 'Wijzigen opent in de echte omgeving de keuze tussen Flex, Basis en Duo.'; return; }
if (g === '1') { err.textContent = ''; go(1); if (cancelled) note.textContent = ''; return; }
if (g === '2') { note.textContent = ''; err.textContent = ''; go(2); return; }
if (g === 'undo') { cancelled = false; go(1); setTimeout(() => { note.textContent = 'Opzegging ingetrokken. Je abonnement loopt gewoon door.'; }, 60); return; }
if (g === '3') {
if (b.getAttribute('aria-busy') === 'true') return;
err.textContent = ''; b.setAttribute('aria-busy', 'true'); const label = b.textContent; b.textContent = 'Bezig met opzeggen...';
setTimeout(() => {
b.removeAttribute('aria-busy'); b.textContent = label;
if (demo.checked) { err.textContent = 'Opzeggen lukte niet door een storing bij ons. Er is niets gewijzigd. Probeer het zo opnieuw, of bel 030 123 4567.'; b.focus(); return; }
const d = dates(); cancelled = true;
set('.ozf__end', fD.format(d.end)); set('.ozf__last', d.last);
set('.ozf__got', fT.format(d.now)); set('.ozf__ref', 'OPZ-' + d.now.getFullYear() + '-' + String(48213 + d.now.getMinutes()).padStart(5, '0'));
go(3);
}, 800);
}
});
}
init(document.querySelector('.jouw-container'));
Meer uit formulieren & invoer
Iets gezien dat je mooi vindt?
Zet het in je selectie en stuur hem op. Dan bouwen we je site eromheen, in jouw huisstijl.
Neem contact op →