Letters als elastiek New
Grab a letter of the heading and pull: it stretches like an elastic band, its neighbours stretch a little too and everything springs back on release. Keyboard users pull with the arrow keys. For the hero of a physiotherapist, gym or yoga studio, or a playful 404 page.
Rek mij uit
Sleep aan een letter of gebruik de pijltjes. Bij Fysio Lunetten in Utrecht veert alles weer terug.
How to use it
- Paste the HTML where the text animations 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.
<!-- Letters als elastiek · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie -->
<div class="jouw-container">
<div class="t7e">
<h3 class="t7e__h" tabindex="0" aria-describedby="t7e-hint"><span class="t7e__sr">Rek mij uit</span><span class="t7e__w" aria-hidden="true">Rek mij uit</span></h3>
<p class="t7e__p" id="t7e-hint">Sleep aan een letter of gebruik de pijltjes. Bij Fysio Lunetten in Utrecht veert alles weer terug.</p>
</div>
</div>/* Letters als elastiek · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie */
.t7e{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:16px;padding:0 20px;container-type:size;font-family:'Switzer',sans-serif;user-select:none;-webkit-user-select:none;box-sizing:border-box}
.t7e__h{margin:0;padding:6px 10px;font-weight:900;font-size:clamp(34px,13cqi,64px);line-height:1;letter-spacing:-.03em;color:#0a0a0a;white-space:nowrap;border-radius:4px;outline:none}
.t7e__h:focus-visible{outline:2px solid #F5480F;outline-offset:4px}
.t7e__c{display:inline-block;cursor:grab;touch-action:none;transform-origin:50% 50%;transition:color .18s}
.t7e__c.is-on{color:#F5480F}
.t7e__sp{display:inline-block;width:.24em}
.t7e__sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.t7e__p{margin:0;max-width:30em;font-size:clamp(12px,3.4cqi,15px);line-height:1.45;color:#4a4a4a;text-align:center;text-wrap:balance}// Letters als elastiek · © 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 w=root.querySelector('.t7e'),h=w.querySelector('.t7e__h'),box=w.querySelector('.t7e__w'),txt=box.textContent;box.textContent='';
var L=[];txt.split('').forEach(function(ch){var s=document.createElement('span');if(ch===' '){s.className='t7e__sp';box.appendChild(s);return;}s.className='t7e__c';s.textContent=ch;box.appendChild(s);L.push({el:s,x:0,y:0,vx:0,vy:0,tx:0,ty:0});});
var reduce=matchMedia('(prefers-reduced-motion: reduce)').matches,drag=null,raf=0,sel=0,MAX=80;
function draw(o){var len=Math.sqrt(o.x*o.x+o.y*o.y);if(len<.3){o.el.style.transform='';return;}var a=Math.atan2(o.y,o.x)*180/Math.PI,base=Math.max(o.el.offsetWidth,o.el.offsetHeight*.55),sc=1+len/base;
o.el.style.transform='translate('+(o.x/2).toFixed(2)+'px,'+(o.y/2).toFixed(2)+'px) rotate('+a.toFixed(2)+'deg) scale('+sc.toFixed(3)+','+(1/Math.sqrt(sc)).toFixed(3)+') rotate('+(-a).toFixed(2)+'deg)';}
function tick(){var moving=false;L.forEach(function(o){if(drag&&drag.o===o){o.x=o.tx;o.y=o.ty;o.vx=o.vy=0;}else if(drag){o.x+=(o.tx-o.x)*.3;o.y+=(o.ty-o.y)*.3;}else if(reduce){o.x=o.y=o.vx=o.vy=0;}else{o.vx=(o.vx-o.x*.16)*.84;o.vy=(o.vy-o.y*.16)*.84;o.x+=o.vx;o.y+=o.vy;}
if(Math.abs(o.x)+Math.abs(o.y)+Math.abs(o.vx)+Math.abs(o.vy)>.06)moving=true;else if(!drag){o.x=o.y=o.vx=o.vy=0;}draw(o);});raf=(moving||drag)?requestAnimationFrame(tick):0;}
function go(){if(!raf)raf=requestAnimationFrame(tick);}
box.addEventListener('pointerdown',function(e){var t=e.target.closest('.t7e__c');if(!t)return;var i=-1;L.forEach(function(o,k){if(o.el===t)i=k;});if(i<0)return;e.preventDefault();try{t.setPointerCapture(e.pointerId);}catch(_){}drag={o:L[i],i:i,sx:e.clientX,sy:e.clientY,id:e.pointerId};t.classList.add('is-on');t.style.cursor='grabbing';go();});
box.addEventListener('pointermove',function(e){if(!drag||e.pointerId!==drag.id)return;var dx=e.clientX-drag.sx,dy=e.clientY-drag.sy,l=Math.sqrt(dx*dx+dy*dy);if(l>MAX){var f=MAX+(l-MAX)*.15;dx=dx/l*f;dy=dy/l*f;}
L.forEach(function(o,k){var d=Math.abs(k-drag.i),f=d===0?1:d===1?.32:d===2?.1:0;o.tx=dx*f;o.ty=dy*f;});});
function end(){if(!drag)return;drag.o.el.classList.remove('is-on');drag.o.el.style.cursor='';L.forEach(function(o){o.tx=o.ty=0;});drag=null;go();}
box.addEventListener('pointerup',end);box.addEventListener('pointercancel',end);box.addEventListener('lostpointercapture',end);
h.addEventListener('keydown',function(e){var m={ArrowLeft:[-1,0],ArrowRight:[1,0],ArrowUp:[0,-1],ArrowDown:[0,1]}[e.key];if(!m)return;e.preventDefault();var o=L[sel];o.x+=m[0]*55;o.y+=m[1]*55;if(L[sel+1]){L[sel+1].x+=m[0]*16;L[sel+1].y+=m[1]*16;}
o.el.classList.add('is-on');setTimeout(function(){o.el.classList.remove('is-on');},450);sel=(sel+1)%L.length;go();});
if(!reduce&&'IntersectionObserver' in window){var io=new IntersectionObserver(function(en){if(!en[0].isIntersecting)return;io.disconnect();setTimeout(function(){if(drag)return;L[1].x=-6;L[1].y=-62;L[0].y=-18;L[2].y=-18;go();},500);},{threshold:.6});io.observe(w);}
}
init(document.querySelector('.jouw-container'));
More text animations
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 →