Open-hours widget maker
Set your weekly hours and get a copy-paste HTML snippet that shows a live “Open now / Closed” badge on your website. No sign-up, no libraries, nothing to host — it runs in your visitors’ browsers.
SundayClosed
Monday
–
Tuesday
–
Wednesday
–
Thursday
–
Friday
–
Saturday
–
Tip: if you close after midnight, set the closing time earlier than the opening time (e.g. 18:00 – 02:00) and the widget treats it as overnight.
Live preview
My BusinessChecking…
- SundayClosed
- Monday9:00 AM – 5:00 PM
- Tuesday9:00 AM – 5:00 PM
- Wednesday9:00 AM – 5:00 PM
- Thursday9:00 AM – 5:00 PM
- Friday9:00 AM – 5:00 PM
- Saturday10:00 AM – 4:00 PM
The status updates itself in your visitors’ browsers — no server needed.
Paste this on your site
<!-- Opening-hours widget by NorthLuma — paste anywhere on your site. No dependencies. -->
<div class="nl-hours" id="nl-hours-k4e4ce">
<div class="nl-hours-head">
<strong>My Business</strong>
<span class="nl-status" data-status>Checking…</span>
</div>
<ul class="nl-hours-list">
<li data-day="0"><span class="nl-day">Sunday</span><span class="nl-time">Closed</span></li>
<li data-day="1"><span class="nl-day">Monday</span><span class="nl-time">9:00 AM – 5:00 PM</span></li>
<li data-day="2"><span class="nl-day">Tuesday</span><span class="nl-time">9:00 AM – 5:00 PM</span></li>
<li data-day="3"><span class="nl-day">Wednesday</span><span class="nl-time">9:00 AM – 5:00 PM</span></li>
<li data-day="4"><span class="nl-day">Thursday</span><span class="nl-time">9:00 AM – 5:00 PM</span></li>
<li data-day="5"><span class="nl-day">Friday</span><span class="nl-time">9:00 AM – 5:00 PM</span></li>
<li data-day="6"><span class="nl-day">Saturday</span><span class="nl-time">10:00 AM – 4:00 PM</span></li>
</ul>
</div>
<style>
#nl-hours-k4e4ce.nl-hours{max-width:320px;font-family:system-ui,-apple-system,Segoe UI,Roboto,sans-serif;border:1px solid #e5e7eb;border-radius:12px;padding:16px;color:#111827;background:#fff}
#nl-hours-k4e4ce .nl-hours-head{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:10px}
#nl-hours-k4e4ce .nl-status{font-size:12px;font-weight:600;padding:2px 8px;border-radius:999px;background:#f3f4f6;color:#6b7280;white-space:nowrap}
#nl-hours-k4e4ce .nl-status.nl-open{background:rgba(22,163,74,.12);color:#15803d}
#nl-hours-k4e4ce .nl-status.nl-closed{background:rgba(220,38,38,.10);color:#b91c1c}
#nl-hours-k4e4ce .nl-hours-list{list-style:none;margin:0;padding:0;font-size:14px}
#nl-hours-k4e4ce .nl-hours-list li{display:flex;justify-content:space-between;padding:4px 0;border-top:1px solid #f3f4f6}
#nl-hours-k4e4ce .nl-hours-list li:first-child{border-top:0}
#nl-hours-k4e4ce .nl-hours-list li.nl-today{font-weight:600;color:#2563eb}
#nl-hours-k4e4ce .nl-time{color:#6b7280}
#nl-hours-k4e4ce .nl-hours-list li.nl-today .nl-time{color:#2563eb}
</style>
<script>
(function(){
var week=[[1,600,960],[0,540,1020],[0,540,1020],[0,540,1020],[0,540,1020],[0,540,1020],[0,600,960]];
var tz="Europe/Stockholm";
var root=document.getElementById("nl-hours-k4e4ce");
if(!root)return;
function fmt(m){var h=Math.floor(m/60),mm=m%60,p=h>=12&&h<24?"PM":"AM";h=h%12;if(h===0)h=12;return h+":"+(mm<10?"0":"")+mm+" "+p;}
function nowInTz(){
try{
var parts=new Intl.DateTimeFormat("en-US",{timeZone:tz,weekday:"short",hour:"2-digit",minute:"2-digit",hour12:false}).formatToParts(new Date());
var map={};parts.forEach(function(p){map[p.type]=p.value;});
var days={Sun:0,Mon:1,Tue:2,Wed:3,Thu:4,Fri:5,Sat:6};
var hh=parseInt(map.hour,10)%24;
return {dow:days[map.weekday],min:hh*60+parseInt(map.minute,10)};
}catch(e){var d=new Date();return {dow:d.getDay(),min:d.getHours()*60+d.getMinutes()};}
}
function status(){
var n=nowInTz(),dow=n.dow,min=n.min;
var y=week[(dow+6)%7];
if(!y[0]&&y[2]<=y[1]&&min<y[2])return {o:1,d:"until "+fmt(y[2])};
var t=week[dow];
if(!t[0]){var ov=t[2]<=t[1];var open=ov?min>=t[1]:(min>=t[1]&&min<t[2]);
if(open)return {o:1,d:"until "+fmt(t[2])};
if(min<t[1])return {o:0,d:"Opens today "+fmt(t[1])};}
var dn=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];
for(var i=1;i<=7;i++){var dd=week[(dow+i)%7];if(!dd[0])return {o:0,d:"Opens "+(i===1?"tomorrow":dn[(dow+i)%7])+" "+fmt(dd[1])};}
return {o:0,d:""};
}
function render(){
var s=status(),n=nowInTz();
var el=root.querySelector("[data-status]");
el.textContent=(s.o?"Open now":"Closed")+(s.d?" · "+s.d:"");
el.className="nl-status "+(s.o?"nl-open":"nl-closed");
root.querySelectorAll("li").forEach(function(li){li.classList.toggle("nl-today",parseInt(li.getAttribute("data-day"),10)===n.dow);});
}
render();setInterval(render,60000);
})();
</script>Self-contained: HTML, styles and a tiny script in one block. No libraries, no external calls. Works in any site builder that allows a custom HTML/embed block.
Need a website to paste it into?
Every local business needs a clean “is it open right now?” answer — and a real site to put it on. NorthLuma builds you one in seconds. Preview it free, then own the source — $49 once, no subscription, no lock-in.
Build my free website Why a live open-hours widget matters
- “Are they open now?” is the #1 question. A live badge answers it before a visitor has to do mental timezone math.
- It builds trust. Accurate, real-time hours signal that the rest of your information is current too.
- Keep your hours in one place. Match this widget to your Google Business Profile and your front door so nobody shows up to a locked entrance.
- Plan for overnight and split shifts. Bars and kitchens often close after midnight — this widget handles spans that cross midnight correctly.
- Set the right timezone. The status is computed in the timezone you choose, so a visitor abroad still sees whether you’re open where you are.
The snippet is one self-contained block of HTML, CSS and vanilla JavaScript — no jQuery, no framework, no external request. It updates every minute on its own. Free and unlimited.