{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"bill-splitter","type":"registry:component","title":"Bill Split Calculator","description":"Estimate an equal per-person share with editable tax and tip.","author":"Notion Arena","categories":["business"],"tags":["widget","free","bill split","tip calculator","tax","calculator","finance"],"meta":{"kind":"widget","tier":"free","version":"1.0.0","updatedAt":"2026-10-11","notionPlan":"Free","emoji":"🧾","delivery":["embed","html-block","download"],"capabilities":{"interactive":true,"offlineSafe":true,"persistsLocally":false,"writesToNotion":false,"needsNetwork":false},"embedUrl":"https://notionarena.vercel.app/embed/bill-splitter","fileUrl":"https://notionarena.vercel.app/widgets/bill-splitter.html","downloadUrl":"https://notionarena.vercel.app/api/widget/bill-splitter","height":310,"minHeight":240,"maxHeight":400,"params":[{"key":"label","label":"Widget title","type":"text","default":"Bill splitter"},{"key":"currency","label":"Currency label","type":"text","default":"$"},{"key":"subtotal","label":"Subtotal","type":"number","default":0,"min":0,"max":100000000,"step":0.01},{"key":"people","label":"People","type":"number","default":2,"min":1,"max":100,"step":1},{"key":"tip","label":"Tip percent","type":"number","default":18,"min":0,"max":100,"step":0.5},{"key":"tax","label":"Tax percent","type":"number","default":0,"min":0,"max":100,"step":0.1},{"key":"accent","label":"Accent","type":"color","default":"#2383e2"},{"key":"theme","label":"Theme","type":"select","default":"auto","options":[{"value":"auto","label":"Match Notion"},{"value":"light","label":"Light"},{"value":"dark","label":"Dark"}]}]},"files":[{"path":"widgets/bill-splitter.html","type":"registry:file","target":"notion/widgets/bill-splitter.html","content":"<!doctype html>\n<html lang=\"en\" data-theme=\"auto\">\n<head>\n<meta charset=\"utf-8\" /><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\" />\n<title>Bill Splitter</title>\n<style>\n:root{--bg:#fff;--fg:#37352f;--muted:#787774;--surface:#f7f7f5;--border:#e9e9e7;--accent:#2383e2;--accent-ink:#fff;--accent-text:var(--accent)--font:ui-sans-serif,-apple-system,BlinkMacSystemFont,\"Segoe UI\",Helvetica,Arial,sans-serif}\nhtml[data-theme=\"dark\"]{--bg:#191919;--fg:#e6e6e4;--muted:#9b9a97;--surface:#252525;--border:#343434}\n@media(prefers-color-scheme:dark){html[data-theme=\"auto\"]{--bg:#191919;--fg:#e6e6e4;--muted:#9b9a97;--surface:#252525;--border:#343434}}\n*{box-sizing:border-box}html,body{margin:0;height:100%}body{background:var(--bg);color:var(--fg);font-family:ui-sans-serif,-apple-system,BlinkMacSystemFont,\"Segoe UI\",Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;overflow:hidden}\n.wrap{height:100%;min-height:240px;display:flex;flex-direction:column;gap:10px;padding:14px;overflow:auto}.head{display:flex;align-items:center;justify-content:space-between;gap:8px}.kicker{font-size:9px;text-transform:uppercase;letter-spacing:.1em;color:var(--muted);font-weight:650}.title{font-size:14px;font-weight:650;margin-top:2px}.fields{display:grid;grid-template-columns:1fr 1fr;gap:7px}.field{display:flex;min-width:0;flex-direction:column;gap:4px}.field label{font-size:10px;color:var(--muted);font-weight:600}.field input{height:32px;border:1px solid var(--border);border-radius:7px;background:var(--surface);color:var(--fg);padding:5px 7px;font:inherit;font-size:12px;font-variant-numeric:tabular-nums}.field input:focus-visible{outline:2px solid var(--accent);outline-offset:1px}.result{display:flex;flex:1;min-height:80px;flex-direction:column;align-items:center;justify-content:center;gap:4px;border:1px solid var(--border);border-radius:10px;background:var(--surface);text-align:center;padding:10px}.per-person{font-size:clamp(28px,8vw,42px);font-weight:650;letter-spacing:-.05em;color:var(--accent-text);font-variant-numeric:tabular-nums}.caption{font-size:10px;color:var(--muted)}.breakdown{display:grid;grid-template-columns:repeat(3,1fr);gap:5px}.part{padding:6px 4px;border:1px solid var(--border);border-radius:7px;text-align:center}.part span{display:block;font-size:8.5px;color:var(--muted)}.part b{font-size:10px;font-variant-numeric:tabular-nums}.note{font-size:9px;line-height:1.35;text-align:center;color:var(--muted)}\n@media(max-width:330px){.wrap{padding:10px}.fields{gap:5px}}\n@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important;scroll-behavior:auto!important}}\n</style>\n</head>\n<body><main class=\"wrap\">\n  <header class=\"head\"><div><div class=\"kicker\">Quick estimate</div><div class=\"title\" id=\"title\">Bill splitter</div></div></header>\n  <section class=\"fields\"><div class=\"field\"><label for=\"subtotal\">Subtotal</label><input id=\"subtotal\" type=\"number\" min=\"0\" max=\"100000000\" step=\"0.01\" /></div><div class=\"field\"><label for=\"people\">People</label><input id=\"people\" type=\"number\" min=\"1\" max=\"100\" step=\"1\" /></div><div class=\"field\"><label for=\"tip\">Tip percent</label><input id=\"tip\" type=\"number\" min=\"0\" max=\"100\" step=\"0.5\" /></div><div class=\"field\"><label for=\"tax\">Tax percent</label><input id=\"tax\" type=\"number\" min=\"0\" max=\"100\" step=\"0.1\" /></div></section>\n  <section class=\"result\" aria-live=\"polite\"><div class=\"caption\">Each person pays</div><div class=\"per-person\" id=\"each\">$0.00</div><div class=\"caption\" id=\"total\">Total: $0.00</div></section>\n  <section class=\"breakdown\"><div class=\"part\"><span>Subtotal</span><b id=\"baseOut\">$0</b></div><div class=\"part\"><span>Tax</span><b id=\"taxOut\">$0</b></div><div class=\"part\"><span>Tip</span><b id=\"tipOut\">$0</b></div></section>\n  <div class=\"note\">Tax and tip are calculated from the entered subtotal, then divided equally. Nothing is saved or sent.</div>\n</main>\n<script>\n(function(){\n  var cfgEl=document.getElementById('bk-config'),base={};try{base=cfgEl?JSON.parse(cfgEl.textContent||'{}'):{};}catch(e){}\n  var q=new URLSearchParams(location.search),c={};for(var k in base)c[k]=base[k];q.forEach(function(v,k){c[k]=v;});\n  function safeColor(v,d){return /^#[0-9a-f]{6}$/i.test(String(v||''))?String(v):d;}\n  function rgb(hex){var s=String(hex).slice(1);return [0,2,4].map(function(i){return parseInt(s.slice(i,i+2),16);});}\n  function luminance(values){return values.map(function(v){v/=255;return v<=.04045?v/12.92:Math.pow((v+.055)/1.055,2.4);}).reduce(function(a,v,i){return a+v*[.2126,.7152,.0722][i];},0);}\n  function contrast(a,b){var x=luminance(a),y=luminance(b);return (Math.max(x,y)+.05)/(Math.min(x,y)+.05);}\n  function accentInk(hex){var c=rgb(hex);return contrast(c,[255,255,255])>=contrast(c,[0,0,0])?'#fff':'#000';}\n  function accentText(hex){var dark=theme==='dark'||(theme==='auto'&&window.matchMedia&&window.matchMedia('(prefers-color-scheme: dark)').matches),bg=rgb(dark?'#252525':'#f7f7f5'),base=rgb(hex),target=dark?[255,255,255]:[0,0,0];if(contrast(base,bg)>=4.5)return hex;for(var t=.02;t<=1;t+=.02){var mix=base.map(function(v,i){return Math.round(v+(target[i]-v)*t);});if(contrast(mix,bg)>=4.5)return '#'+mix.map(function(v){return v.toString(16).padStart(2,'0');}).join('');}return dark?'#fff':'#191919';}\n  function setAccentText(){document.documentElement.style.setProperty('--accent-text',accentText(ACCENT));}\n  function val(k,d){var n=parseFloat(c[k]);return isFinite(n)?n:d;}\n  var theme=['auto','light','dark'].indexOf(String(c.theme||'auto'))>-1?String(c.theme||'auto'):'auto',ACCENT=safeColor(c.accent,'#2383e2'),LABEL=String(c.label||'Bill splitter').slice(0,48),CURRENCY=String(c.currency||'$').slice(0,6);\n  document.documentElement.setAttribute('data-theme',theme);document.documentElement.style.setProperty('--accent',ACCENT);document.documentElement.style.setProperty('--accent-ink',accentInk(ACCENT));setAccentText();if(theme==='auto'&&window.matchMedia){var scheme=window.matchMedia('(prefers-color-scheme: dark)');if(scheme.addEventListener)scheme.addEventListener('change',setAccentText);else if(scheme.addListener)scheme.addListener(setAccentText);}document.getElementById('title').textContent=LABEL;document.title=LABEL;\n  var ids=['subtotal','people','tip','tax'];ids.forEach(function(id){document.getElementById(id).value=String(val(id,id==='people'?2:(id==='subtotal'?0:0)));document.getElementById(id).addEventListener('input',calculate);});\n  function money(n){return CURRENCY+' '+Number(n).toLocaleString(undefined,{minimumFractionDigits:2,maximumFractionDigits:2});}\n  function calculate(){var base=Math.max(0,Math.min(1e8,parseFloat(document.getElementById('subtotal').value)||0)),people=Math.max(1,Math.min(100,parseInt(document.getElementById('people').value,10)||1)),tipRate=Math.max(0,Math.min(100,parseFloat(document.getElementById('tip').value)||0)),taxRate=Math.max(0,Math.min(100,parseFloat(document.getElementById('tax').value)||0)),tip=base*tipRate/100,tax=base*taxRate/100,total=base+tip+tax;document.getElementById('each').textContent=money(total/people);document.getElementById('total').textContent='Total: '+money(total)+' · '+people+' '+(people===1?'person':'people');document.getElementById('baseOut').textContent=money(base);document.getElementById('taxOut').textContent=money(tax);document.getElementById('tipOut').textContent=money(tip);}\n  calculate();\n})();\n</script>\n</body>\n</html>\n"}]}