Omlaag trekken met veer New
An order list you pull down to refresh: the further you pull, the heavier it gets, and in the gap a coil spring stretches along that vibrates while loading and then snaps back. New orders slide in at the top. Also works with the Refresh button. For an order or route overview in the web app of a bakery, courier or contractor. With reduced motion it refreshes without the spring.
Bestellingen vandaag
- #24172 desembrodenDelft, 08:10
- #2416Appeltaart grootRijswijk, 07:55
- #241512 krentenbollenDelft, 07:40
- #2414Speltbrood heelDen Hoorn, 07:32
- #24134 saucijzenbroodjesDelft, 07:15
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.
<!-- Omlaag trekken met veer · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie -->
<div class="jouw-container">
<div class="fyp">
<div class="fyp__kop"><h3 class="fyp__h">Bestellingen vandaag</h3><button class="fyp__ver" type="button">Vernieuwen</button></div>
<div class="fyp__vak">
<div class="fyp__trek" aria-hidden="true"><span class="fyp__tip">Trek omlaag om te vernieuwen</span><svg class="fyp__veer"><path d=""/></svg></div>
<ul class="fyp__lijst" aria-label="Bestellingen, trek omlaag om te vernieuwen">
<li class="fyp__item"><b>#2417</b><span>2 desembroden</span><span class="fyp__waar">Delft, 08:10</span></li>
<li class="fyp__item"><b>#2416</b><span>Appeltaart groot</span><span class="fyp__waar">Rijswijk, 07:55</span></li>
<li class="fyp__item"><b>#2415</b><span>12 krentenbollen</span><span class="fyp__waar">Delft, 07:40</span></li>
<li class="fyp__item"><b>#2414</b><span>Speltbrood heel</span><span class="fyp__waar">Den Hoorn, 07:32</span></li>
<li class="fyp__item"><b>#2413</b><span>4 saucijzenbroodjes</span><span class="fyp__waar">Delft, 07:15</span></li>
</ul>
</div>
<p class="fyp__sr" aria-live="polite"></p>
</div>
</div>/* Omlaag trekken met veer · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie */
.fyp{position:absolute;inset:0;display:flex;flex-direction:column;background:#fff;color:#0a0a0a;font-family:'Switzer',sans-serif;text-align:left}
.fyp *{box-sizing:border-box}
.fyp__kop{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:10px 14px;border-bottom:1px solid rgba(10,10,10,.14);background:#fff;position:relative;z-index:2}
.fyp__h{margin:0;font:700 16px/1.2 'Switzer',sans-serif;letter-spacing:-.01em}
.fyp__ver{margin:0;padding:8px 11px;border:1px solid #0a0a0a;border-radius:4px;background:#fff;color:#0a0a0a;font:600 13px/1 'Switzer',sans-serif;cursor:pointer;transition:background-color .16s}
.fyp__ver:hover{background:#f4f3f1}
.fyp__ver:focus-visible{outline:2px solid #F5480F;outline-offset:2px}
.fyp__vak{position:relative;flex:1;overflow:hidden;background:#f4f3f1;touch-action:none;cursor:grab;user-select:none;-webkit-user-select:none}
.fyp__vak:active{cursor:grabbing}
.fyp__trek{position:absolute;left:0;right:0;top:0;height:0;overflow:hidden;display:flex;align-items:center;gap:12px;padding:0 14px}
.fyp__tip{font:500 12px/1.2 'Switzer',sans-serif;color:#3d3b37;white-space:nowrap}
.fyp__veer{width:26px;height:100%;flex:0 0 26px;margin-left:auto;margin-right:18%;overflow:visible}
.fyp__veer path{fill:none;stroke:#F5480F;stroke-width:2.2;stroke-linejoin:round;stroke-linecap:round}
.fyp__lijst{list-style:none;margin:0;padding:0;background:#fff;will-change:transform}
.fyp__item{display:grid;grid-template-columns:auto 1fr auto;gap:10px;align-items:baseline;padding:9px 14px;border-bottom:1px solid rgba(10,10,10,.08);font:400 13px/1.3 'Switzer',sans-serif;box-shadow:inset 3px 0 0 transparent;transition:box-shadow 1.2s ease}
.fyp__item b{font-weight:700}
.fyp__waar{color:#5c5a56;font-size:12px;white-space:nowrap}
.fyp__item.is-nieuw{box-shadow:inset 3px 0 0 #F5480F;background:#fff7f3}
.fyp__sr{position:absolute;width:1px;height:1px;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}// Omlaag trekken met veer · © 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){
var el=root.querySelector('.fyp');if(!el)return;
var RM=window.matchMedia&&window.matchMedia('(prefers-reduced-motion: reduce)').matches;
var vak=el.querySelector('.fyp__vak'),trek=el.querySelector('.fyp__trek'),tip=el.querySelector('.fyp__tip'),veer=el.querySelector('.fyp__veer'),pad=veer.querySelector('path'),lijst=el.querySelector('.fyp__lijst'),knop=el.querySelector('.fyp__ver'),sr=el.querySelector('.fyp__sr');
var off=0,v=0,doel=0,modus='rust',raf=0,last=0,y0=0,drag=false,trilT=0,DREMPEL=54,ni=0;
var NIEUW=[['#2418','6 krentenbollen','Delft, 09:02'],['#2419','Appeltaart klein','Rijswijk, 09:15'],['#2420','2 speltbroden','Den Hoorn, 09:31'],['#2421','Taart 8 personen','Delft, 09:48']];
function rubber(d){return 112*(1-Math.exp(-d/150));}
function teken(t){var h=Math.max(0,off),tril=modus==='laden'?Math.sin(t*.022)*3.5:0,hv=Math.max(0,h+tril);
lijst.style.transform='translateY('+off.toFixed(1)+'px)';trek.style.height=h.toFixed(1)+'px';
var n=8,d='M13 0';for(var i=1;i<n;i++)d+=' L'+(i%2?2:24)+' '+(hv*i/n).toFixed(1);d+=' L13 '+hv.toFixed(1);pad.setAttribute('d',d);
tip.style.opacity=h>26?1:0;tip.textContent=modus==='laden'?'Bijwerken':(off>=DREMPEL?'Laat los om te vernieuwen':'Trek omlaag om te vernieuwen');}
function voegToe(){var it=NIEUW[ni++];if(!it){sr.textContent='Geen nieuwe bestellingen.';return;}
var li=document.createElement('li');li.className='fyp__item is-nieuw';li.innerHTML='<b></b><span></span><span class="fyp__waar"></span>';li.children[0].textContent=it[0];li.children[1].textContent=it[1];li.children[2].textContent=it[2];
lijst.insertBefore(li,lijst.firstChild);while(lijst.children.length>6)lijst.removeChild(lijst.lastChild);setTimeout(function(){li.classList.remove('is-nieuw');},1600);
sr.textContent='Nieuwe bestelling '+it[0]+': '+it[1]+', '+it[2]+'.';}
function tick(t){var dt=Math.min(.033,(t-last)/1000);last=t;
if(!drag){var k=modus==='terug'?190:240,c=modus==='terug'?11:20;for(var i=0;i<3;i++){v+=((doel-off)*k-v*c)*dt/3;off+=v*dt/3;}}
teken(t);if(modus==='laden'&&t>trilT){modus='terug';doel=0;voegToe();}
if(!drag&&modus==='terug'&&Math.abs(off)<.2&&Math.abs(v)<.5){off=0;v=0;modus='rust';teken(t);raf=0;return;}raf=requestAnimationFrame(tick);}
function kick(){if(!raf){last=performance.now();raf=requestAnimationFrame(tick);}}
function laad(){if(RM){off=0;teken(0);voegToe();modus='rust';return;}modus='laden';doel=46;trilT=performance.now()+1150;kick();}
vak.addEventListener('pointerdown',function(e){if(e.button>0||modus==='laden')return;drag=true;y0=e.clientY;modus='trek';try{vak.setPointerCapture(e.pointerId);}catch(_){}kick();});
vak.addEventListener('pointermove',function(e){if(!drag)return;off=rubber(Math.max(0,e.clientY-y0));v=0;if(RM)teken(0);});
function los(){if(!drag)return;drag=false;if(off>=DREMPEL)laad();else{modus='terug';doel=0;if(RM){off=0;teken(0);modus='rust';}else kick();}}
vak.addEventListener('pointerup',los);vak.addEventListener('pointercancel',los);
knop.addEventListener('click',function(){if(modus==='rust'||modus==='terug')laad();});
teken(0);
}
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 →