Date Range Picker
A month calendar where you click a start and end day and the range highlights with a hover preview.
Preview and code
index.html
<div class='rp'><div class='rp-h'><button id='rpp' aria-label='Previous month'>‹</button><b id='rpt'></b><button id='rpn' aria-label='Next month'>›</button></div><p id='rps'>Select a date range</p><div class='rp-w'><span>S</span><span>M</span><span>T</span><span>W</span><span>T</span><span>F</span><span>S</span></div><div class='rp-g' id='rpg'></div></div>
styles.css
.rp{width:310px;margin:auto;padding:16px 18px 18px;background:#fff;border-radius:20px;box-shadow:0 4px 24px rgba(0,0,0,.08);font-family:Inter,Arial,sans-serif;color:#111}.rp-h{display:flex;justify-content:space-between;align-items:center}.rp-h b{font-size:15px;font-weight:600}.rp-h button{width:28px;height:28px;border:0;border-radius:8px;background:none;font-size:22px;line-height:1;color:#555;cursor:pointer}.rp-h button:hover{background:#f4f4f4}.rp p{margin:12px 0 10px;font-size:13px;color:#737373}.rp-w,.rp-g{display:grid;grid-template-columns:repeat(7,1fr);text-align:center}.rp-w span{font-size:11px;font-weight:600;color:#9a9a9a;padding-bottom:8px}.rp-g button{height:38px;border:0;background:none;font:inherit;font-size:15px;color:#222;cursor:pointer;border-radius:0}.rp-g button.in{background:#f0f0f0}.rp-g button.s{background:#111;color:#fff;border-radius:19px 0 0 19px}.rp-g button.e{background:#111;color:#fff;border-radius:0 19px 19px 0}.rp-g button.s.e{border-radius:19px}.rp-g button:hover:not(.s):not(.e):not(.in){border-radius:19px;background:#f4f4f4}
script.js
const now=new Date();let y=now.getFullYear(),m=now.getMonth(),a=null,b=null,hv=null;const g=document.getElementById('rpg'),t=document.getElementById('rpt'),s=document.getElementById('rps');const key=d=>new Date(y,m,d).getTime();const fm=x=>new Date(x).toLocaleDateString(undefined,{month:'short',day:'numeric'});const draw=()=>{t.textContent=new Date(y,m,1).toLocaleDateString(undefined,{month:'long',year:'numeric'});const f=new Date(y,m,1).getDay(),n=new Date(y,m+1,0).getDate();let h='';for(let i=0;i<f;i++)h+='<i></i>';for(let d=1;d<=n;d++){const k=key(d);const end=b||(a&&hv&&hv>a?hv:null);let c='';if(a&&k===a)c+=' s';if(end&&k===end)c+=' e';if(a&&end&&k>a&&k<end)c+=' in';if(a&&!end&&k===a)c+=' e';h+='<button class="'+c+'" data-d='+d+'>'+d+'</button>'}g.innerHTML=h;s.textContent=a&&b?fm(a)+' – '+fm(b):a?'Pick an end date':'Select a date range'};g.addEventListener('click',e=>{const x=e.target.closest('button');if(!x)return;const k=key(+x.dataset.d);if(!a||b){a=k;b=null}else if(k<a){a=k}else{b=k}draw()});g.addEventListener('mouseover',e=>{const x=e.target.closest('button');if(x&&a&&!b){hv=key(+x.dataset.d);draw()}});document.getElementById('rpp').onclick=()=>{m--;if(m<0){m=11;y--}draw()};document.getElementById('rpn').onclick=()=>{m++;if(m>11){m=0;y++}draw()};draw();
About
Two clicks select a range. Days between are tinted, the endpoints are dark pills, and hovering previews the range before the second click.