Vacatures beoordelen door te slepen Nieuw
Een stapel vacaturekaarten: sleep naar rechts om te bewaren en naar links om over te slaan, of gebruik de knoppen of de pijltjestoetsen. Met een stempel die meekleurt, ongedaan maken, een teller via aria-live en een eindscherm met je bewaarde functies. Voor een werkenbij-site of een uitzendbureau dat kandidaten snel laat kiezen.
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.
<!-- Vacatures beoordelen door te slepen · NedDev · eigen werk. -->
<div class="jouw-container">
<div class="vsk">
<div class="vsk__deck"></div>
<div class="vsk__bar">
<button class="vsk__b vsk__no" type="button">Overslaan</button>
<p class="vsk__st" aria-live="polite">0 bewaard</p>
<button class="vsk__b vsk__undo" type="button" disabled>Terug</button>
<button class="vsk__b vsk__yes" type="button">Bewaren</button>
</div>
</div>
</div>/* Vacatures beoordelen door te slepen · NedDev · eigen werk. */
.vsk{position:absolute;inset:0;display:flex;flex-direction:column;gap:10px;padding:10px 12px 12px;font-family:'Switzer',system-ui,sans-serif;color:#0a0a0a;background:#f4f3f1;text-align:left}
.vsk *{box-sizing:border-box}
.vsk__deck{position:relative;flex:1;min-height:0;max-height:170px;width:min(100%,330px);margin:auto auto 0}
.vsk__card{position:absolute;inset:0;padding:12px 14px;background:#fff;border:1px solid rgba(10,10,10,.14);border-radius:8px;display:flex;flex-direction:column;gap:3px;overflow:hidden;touch-action:pan-y;user-select:none;cursor:grab;transition:transform .3s cubic-bezier(.2,.8,.2,1),opacity .3s;box-shadow:0 6px 16px -10px rgba(10,10,10,.35)}
.vsk__card.is-drag{transition:none;cursor:grabbing}
.vsk__card:focus-visible{outline:2px solid #F5480F;outline-offset:2px}
.vsk__t{margin:0;font-size:16px;line-height:1.2;font-weight:700;letter-spacing:-.01em;padding-right:76px}
.vsk__o{margin:0;font-size:12.5px;color:#4a4a4a}
.vsk__s{margin:6px 0 0;font-size:13px;font-weight:600;font-variant-numeric:tabular-nums}
.vsk__p{margin:0;font-size:12px;color:#4a4a4a;line-height:1.35}
.vsk__stamp{position:absolute;top:12px;right:12px;padding:3px 7px;border:2px solid currentColor;border-radius:4px;font-size:12px;font-weight:700;opacity:0;transform:rotate(8deg);pointer-events:none}
.vsk__stamp--ja{color:#c43a0b}
.vsk__stamp--nee{color:#0a0a0a;transform:rotate(-8deg)}
.vsk__end{position:absolute;inset:0;display:flex;flex-direction:column;justify-content:center;gap:6px;padding:12px 14px;background:#fff;border:1px solid rgba(10,10,10,.14);border-radius:8px;font-size:13px}
.vsk__end p{margin:0}
.vsk__end strong{font-size:15px}
.vsk__end button{align-self:flex-start;margin-top:4px}
.vsk__bar{display:flex;align-items:center;gap:6px;width:min(100%,330px);margin:0 auto auto}
.vsk__st{flex:1;margin:0;font-size:12px;color:#4a4a4a;text-align:center}
.vsk__b{min-height:32px;padding:0 11px;border:1px solid #0a0a0a;border-radius:4px;background:#fff;color:#0a0a0a;font:600 12.5px/1 'Switzer',system-ui,sans-serif;cursor:pointer;transition:background-color .15s,color .15s}
.vsk__b:hover:not(:disabled){background:#0a0a0a;color:#fff}
.vsk__yes{background:#F5480F;border-color:#F5480F}
.vsk__yes:hover:not(:disabled){background:#0a0a0a;border-color:#0a0a0a}
.vsk__b:disabled{opacity:.4;cursor:default}
.vsk__b:focus-visible{outline:2px solid #F5480F;outline-offset:2px}
@media (prefers-reduced-motion:reduce){.vsk__card{transition:none}}// Vacatures beoordelen door te slepen · NedDev · eigen werk.
// root = het element waarin de HTML staat
function init(root){
var w = root.querySelector('.vsk'), deck = w.querySelector('.vsk__deck'), st = w.querySelector('.vsk__st');
var bNo = w.querySelector('.vsk__no'), bYes = w.querySelector('.vsk__yes'), bUndo = w.querySelector('.vsk__undo');
var rm = matchMedia('(prefers-reduced-motion: reduce)').matches;
var D = [
['Servicemonteur warmtepompen', 'Van Dijk Installatie, Zwolle', '€ 3.100 tot € 3.900 · 40 uur', 'Eigen bedrijfsbus en opleiding F-gassen'],
['Planner binnendienst', 'Hendriks Bouw, Nijmegen', '€ 2.900 tot € 3.500 · 32 tot 40 uur', 'Vrijdag thuiswerken, vast contract na een jaar'],
['Doktersassistent', 'Huisartsenpraktijk De Linde, Amersfoort', '€ 2.600 tot € 3.300 · 28 uur', 'Geen avonddiensten, eigen spreekuur'],
['Junior accountmanager', 'Drukkerij Peeters, Tilburg', '€ 3.000 tot € 3.600 · 40 uur', 'Leaseauto na de proeftijd'],
['Medewerker werkplaats', 'Rijwielhuis Spaarne, Haarlem', '€ 2.500 tot € 2.900 · 24 uur', 'Fiets van de zaak, zaterdag om de week']
];
var idx = 0, hist = [], kept = [];
function esc(s) { return s.replace(/&/g, '&').replace(/</g, '<'); }
function count() { st.textContent = kept.length + ' bewaard'; bUndo.disabled = !hist.length; bNo.disabled = bYes.disabled = idx >= D.length; }
function render(focus) {
deck.innerHTML = '';
if (idx >= D.length) {
var e = document.createElement('div'); e.className = 'vsk__end';
e.innerHTML = '<p><strong>Je hebt alle ' + D.length + ' vacatures bekeken.</strong></p><p>' + (kept.length ? 'Bewaard: ' + kept.map(function (i) { return esc(D[i][0]); }).join(', ') + '.' : 'Je hebt niets bewaard.') + '</p><button class="vsk__b vsk__again" type="button">Opnieuw bekijken</button>';
deck.appendChild(e);
e.querySelector('.vsk__again').addEventListener('click', function () { idx = 0; hist = []; kept = []; render(true); count(); });
if (focus) e.querySelector('button').focus();
return;
}
for (var k = Math.min(D.length - 1, idx + 2); k >= idx; k--) {
var d = D[k], c = document.createElement('div'), depth = k - idx;
c.className = 'vsk__card';
c.innerHTML = '<h3 class="vsk__t">' + esc(d[0]) + '</h3><p class="vsk__o">' + esc(d[1]) + '</p><p class="vsk__s">' + esc(d[2]) + '</p><p class="vsk__p">' + esc(d[3]) + '</p><span class="vsk__stamp vsk__stamp--ja" aria-hidden="true">Bewaren</span><span class="vsk__stamp vsk__stamp--nee" aria-hidden="true">Overslaan</span>';
c.style.transform = 'translateY(' + (-depth * 6) + 'px) scale(' + (1 - depth * .04) + ')';
c.style.zIndex = 10 - depth;
if (depth) { c.setAttribute('aria-hidden', 'true'); c.style.opacity = depth > 1 ? .5 : .85; }
else { c.tabIndex = 0; c.setAttribute('role', 'group'); c.setAttribute('aria-label', 'Vacature ' + (k + 1) + ' van ' + D.length + ': ' + d[0] + '. Pijl rechts bewaart, pijl links slaat over.'); bind(c); }
deck.appendChild(c);
}
if (focus) deck.lastChild.focus();
}
function decide(dir) {
if (idx >= D.length) return;
var c = deck.lastChild, had = document.activeElement === c || w.contains(document.activeElement);
hist.push(dir); if (dir > 0) kept.push(idx);
c.style.transition = rm ? 'none' : '';
c.style.transform = 'translateX(' + (dir * 130) + '%) rotate(' + (dir * 14) + 'deg)'; c.style.opacity = 0;
setTimeout(function () { idx++; render(had && document.activeElement !== bNo && document.activeElement !== bYes); count(); }, rm ? 0 : 260);
}
function bind(c) {
var x0 = 0, y0 = 0, dx = 0, on = false, ja = c.querySelector('.vsk__stamp--ja'), nee = c.querySelector('.vsk__stamp--nee');
c.addEventListener('pointerdown', function (e) { if (e.button) return; on = true; x0 = e.clientX; y0 = e.clientY; dx = 0; c.setPointerCapture(e.pointerId); c.classList.add('is-drag'); });
c.addEventListener('pointermove', function (e) {
if (!on) return; dx = e.clientX - x0; var dy = (e.clientY - y0) * .2;
c.style.transform = 'translate(' + dx + 'px,' + dy + 'px) rotate(' + (dx / 22) + 'deg)';
ja.style.opacity = Math.max(0, Math.min(1, dx / 80)); nee.style.opacity = Math.max(0, Math.min(1, -dx / 80));
});
function up() { if (!on) return; on = false; c.classList.remove('is-drag'); if (Math.abs(dx) > 80) decide(dx > 0 ? 1 : -1); else { c.style.transform = ''; ja.style.opacity = nee.style.opacity = 0; } }
c.addEventListener('pointerup', up); c.addEventListener('pointercancel', up);
c.addEventListener('keydown', function (e) { if (e.key === 'ArrowRight') { e.preventDefault(); decide(1); } else if (e.key === 'ArrowLeft') { e.preventDefault(); decide(-1); } });
}
bNo.addEventListener('click', function () { decide(-1); });
bYes.addEventListener('click', function () { decide(1); });
bUndo.addEventListener('click', function () { if (!hist.length) return; var d = hist.pop(); idx--; if (d > 0) kept.pop(); render(false); count(); });
render(false); count();
}
init(document.querySelector('.jouw-container'));
Meer uit componenten
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 →