Prikbord met sleepbare briefjes New
A pinboard with notes, a drawing and stickers you move with mouse or finger: the pin pops off, the note swings with your movement and is pinned again when you let go. With the keyboard you tab to a note and move it with the arrow keys (Shift for larger steps). For a childcare parent page, a team page or an idea wall at a workshop.
Sleep of gebruik de pijltjes
How to use it
- Paste the HTML where the components 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.
<!-- Prikbord met sleepbare briefjes · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie -->
<div class="jouw-container">
<div class="pbs">
<div class="pbs__bord">
<button type="button" class="pbs__ding pbs__ding--memo" style="left:6%;top:9%;--rot:-4deg" aria-label="Briefje: vrijdag pannenkoeken eten. Verplaats met de pijltjestoetsen."><span class="pbs__pin" aria-hidden="true"></span>Vrijdag pannenkoeken eten</button>
<button type="button" class="pbs__ding pbs__ding--foto" style="left:38%;top:8%;--rot:3deg" aria-label="Tekening van Noor: een zon. Verplaats met de pijltjestoetsen."><span class="pbs__pin" aria-hidden="true"></span><svg viewBox="0 0 60 44" aria-hidden="true"><circle cx="30" cy="22" r="9" fill="#F5480F"/><g stroke="#F5480F" stroke-width="3" stroke-linecap="round"><path d="M30 4v6M30 34v6M12 22h6M42 22h6M17 9l4 4M39 31l4 4M43 9l-4 4M21 31l-4 4"/></g></svg><span>Tekening van Noor</span></button>
<button type="button" class="pbs__ding pbs__ding--rond" style="left:70%;top:12%;--rot:8deg" aria-label="Sticker: juf Sanne jarig op 14 november. Verplaats met de pijltjestoetsen."><span class="pbs__pin" aria-hidden="true"></span>Juf Sanne jarig 14 nov</button>
<button type="button" class="pbs__ding pbs__ding--label" style="left:12%;top:58%;--rot:2deg" aria-label="Label: ophalen voor 18.00 uur. Verplaats met de pijltjestoetsen."><span class="pbs__pin" aria-hidden="true"></span>Ophalen voor 18.00 uur</button>
<button type="button" class="pbs__ding pbs__ding--memo2" style="left:50%;top:56%;--rot:-6deg" aria-label="Briefje: regenlaarzen mee op woensdag. Verplaats met de pijltjestoetsen."><span class="pbs__pin" aria-hidden="true"></span>Woensdag regenlaarzen mee</button>
<p class="pbs__hint">Sleep of gebruik de pijltjes</p>
</div>
</div>
</div>/* Prikbord met sleepbare briefjes · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie */
.pbs{width:100%;height:100%;padding:10px;box-sizing:border-box;background:#f4f3f1;font-family:Switzer,sans-serif}
.pbs__bord{position:relative;width:100%;height:100%;border-radius:8px;overflow:hidden;background-color:#d4b48a;background-image:radial-gradient(rgba(90,60,30,.18) 1px,transparent 1.5px),radial-gradient(rgba(255,255,255,.18) 1px,transparent 1.5px);background-size:7px 7px,11px 11px;background-position:0 0,3px 5px;box-shadow:inset 0 0 0 5px #0a0a0a}
.pbs__ding{position:absolute;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;width:92px;min-height:58px;padding:12px 8px 8px;box-sizing:border-box;font:inherit;font-size:13px;line-height:1.2;font-weight:500;text-align:center;color:#0a0a0a;border:0;border-radius:4px;cursor:grab;touch-action:none;user-select:none;transform:rotate(var(--rot,0deg));box-shadow:0 2px 3px rgba(10,10,10,.22);transition:box-shadow .15s}
.pbs__ding--memo{background:#ffe48a}
.pbs__ding--memo2{background:#fff;width:96px}
.pbs__ding--foto{background:#fff;width:84px;padding:12px 6px 6px}
.pbs__ding--foto svg{width:56px;height:40px;background:#f4f3f1;border-radius:4px}
.pbs__ding--foto span{font-size:12px}
.pbs__ding--rond{width:78px;height:78px;min-height:0;border-radius:50%;background:#F5480F;color:#fff;font-weight:600;font-size:12px;padding:16px 8px 8px}
.pbs__ding--label{background:#0a0a0a;color:#fff;width:104px;min-height:40px}
.pbs__pin{position:absolute;top:4px;left:50%;width:9px;height:9px;margin-left:-4.5px;border-radius:50%;background:#0a0a0a;box-shadow:0 1px 1px rgba(0,0,0,.35);transition:transform .2s cubic-bezier(.3,1.6,.5,1),opacity .15s}
.pbs__ding--label .pbs__pin,.pbs__ding--rond .pbs__pin{background:#fff}
.pbs__ding.is-los{cursor:grabbing;box-shadow:0 12px 20px rgba(10,10,10,.28);z-index:50}
.pbs__ding.is-los .pbs__pin{transform:translateY(-10px) scale(.4);opacity:0}
.pbs__ding.is-plop{animation:pbs-plop .3s ease-out}
@keyframes pbs-plop{40%{scale:1.06 .94}100%{scale:1}}
.pbs__ding:focus-visible{outline:2px solid #F5480F;outline-offset:3px}
.pbs__hint{position:absolute;right:12px;bottom:9px;margin:0;font-size:12px;color:#3d2c17}
@media (max-width:420px){.pbs__ding{width:80px;font-size:12px}.pbs__ding--rond{width:66px;height:66px}.pbs__ding--label{width:92px}.pbs__ding--memo2{width:84px}}
@media (prefers-reduced-motion:reduce){.pbs__pin,.pbs__ding{transition:none}.pbs__ding.is-plop{animation:none}}// Prikbord met sleepbare briefjes · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie
// root = het element waarin de HTML staat
function init(root){
const w = root.querySelector('.pbs'); if (!w) return;
const bord = w.querySelector('.pbs__bord');
const rm = matchMedia('(prefers-reduced-motion: reduce)').matches;
let z = 10;
function klem(el, xpx, ypx){
const b = bord.getBoundingClientRect(), r = el.getBoundingClientRect();
const mx = b.width - el.offsetWidth - 6, my = b.height - el.offsetHeight - 6;
xpx = Math.max(6, Math.min(mx, xpx)); ypx = Math.max(6, Math.min(my, ypx));
el.style.left = (xpx / b.width * 100).toFixed(2) + '%'; el.style.top = (ypx / b.height * 100).toFixed(2) + '%';
}
function plop(el){ el.classList.remove('is-plop'); void el.offsetWidth; if (!rm) el.classList.add('is-plop'); }
bord.querySelectorAll('.pbs__ding').forEach(el => {
const basis = parseFloat(getComputedStyle(el).getPropertyValue('--rot')) || 0;
let sleep = null, vx = 0, lx = 0, raf = 0, hoek = basis;
function draai(){
raf = 0; const doelH = basis + Math.max(-14, Math.min(14, vx * 1.4));
hoek += (doelH - hoek) * 0.25; vx *= 0.82;
el.style.transform = 'rotate(' + hoek.toFixed(2) + 'deg)';
if (sleep || Math.abs(hoek - basis) > 0.1) raf = requestAnimationFrame(draai);
else el.style.transform = '';
}
el.addEventListener('pointerdown', e => {
if (e.button > 0) return;
const b = bord.getBoundingClientRect();
sleep = { dx: e.clientX - b.left - el.offsetLeft, dy: e.clientY - b.top - el.offsetTop, id: e.pointerId };
lx = e.clientX; el.setPointerCapture(e.pointerId); el.classList.add('is-los'); el.style.zIndex = ++z;
});
el.addEventListener('pointermove', e => {
if (!sleep || e.pointerId !== sleep.id) return;
const b = bord.getBoundingClientRect();
klem(el, e.clientX - b.left - sleep.dx, e.clientY - b.top - sleep.dy);
vx = e.clientX - lx; lx = e.clientX;
if (!rm && !raf) raf = requestAnimationFrame(draai);
});
const los = () => { if (!sleep) return; sleep = null; el.classList.remove('is-los'); el.style.zIndex = z; plop(el); if (!rm && !raf) raf = requestAnimationFrame(draai); };
el.addEventListener('pointerup', los); el.addEventListener('pointercancel', los);
el.addEventListener('keydown', e => {
const s = e.shiftKey ? 30 : 8; const m = { ArrowLeft:[-s,0], ArrowRight:[s,0], ArrowUp:[0,-s], ArrowDown:[0,s] }[e.key];
if (!m) return; e.preventDefault(); el.style.zIndex = ++z;
klem(el, el.offsetLeft + m[0], el.offsetTop + m[1]);
vx = m[0] / 2; if (!rm && !raf) raf = requestAnimationFrame(draai);
});
el.addEventListener('keyup', e => { if (e.key.indexOf('Arrow') === 0) plop(el); });
});
}
init(document.querySelector('.jouw-container'));
More components
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 →