Floating layers and status feedback

Approval Action Sheet Progress Blocker

Complete the progress blocker in an approval form scenario: includes real content, interactive controls, clear state feedback, and responsive layout.

Floating layers and status feedbackProgress overlayHTMLCSSJavaScript
With JavaScript enabled, you can edit, run, and save this example. The fixed source is as follows:
<!doctype html>
<html lang="en" dir="ltr">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Approval Action Sheet Progress Blocker</title>
  <style>
    :root { --ink:#17241d; --paper:#f3f0e7; --accent:#af4f45; --secondary:#9eb49f; --line:color-mix(in srgb, var(--ink) 18%, transparent); --shadow:0 24px 60px color-mix(in srgb, var(--ink) 16%, transparent); color-scheme:light; }
    * { box-sizing:border-box; }
    html { min-width:320px; background:var(--paper); }
    body { min-height:100vh; margin:0; overflow-x:hidden; color:var(--ink); font-family:"IBM Plex Sans","PingFang SC",sans-serif; background:linear-gradient(color-mix(in srgb,var(--ink) 5%,transparent) 1px,transparent 1px),var(--paper);background-size:100% 36px; }
    button,input,select,textarea { color:inherit; font:inherit; }
    button,[role="button"],input,select,textarea { accent-color:var(--accent); }
    button { cursor:pointer; }
    button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,[tabindex]:focus-visible { outline:3px solid var(--accent); outline-offset:3px; }
    [hidden] { display:none !important; }
    @media (max-width:700px) { .mast h1 { line-height:1.08 !important; letter-spacing:-.035em !important; overflow-wrap:anywhere; } }
    @media (prefers-reduced-motion:reduce) { *,*::before,*::after { scroll-behavior:auto !important; animation-duration:.01ms !important; animation-iteration-count:1 !important; transition-duration:.01ms !important; } }
    .page{width:min(1280px,calc(100% - 24px));margin:auto;padding:28px 0 64px}.mast{display:flex;justify-content:space-between;padding:18px;border:1px solid var(--line);background:color-mix(in srgb,#fff 60%,transparent);gap:18px;margin-bottom:14px}.mast h1{font-family:"IBM Plex Sans","PingFang SC",sans-serif;font-weight:800;font-size:clamp(34px,6vw,66px);letter-spacing:-.045em;margin:0;line-height:1}.eyebrow{display:block;margin-bottom:6px;color:var(--accent);font:800 10px/1 ui-monospace,monospace;letter-spacing:.16em}.intro{max-width:720px;margin:10px 0 0;font-size:14px;line-height:1.6}.scenario{padding:7px 10px;border:1px solid var(--line);border-radius:8px;background:var(--paper);font-size:12px}.demo{border-radius:14px;box-shadow:0 14px 40px color-mix(in srgb,var(--ink) 11%,transparent);position:relative;min-height:390px;overflow:hidden;padding:24px;background:color-mix(in srgb,var(--paper) 90%,#fff)}@media(max-width:700px){.page{width:calc(100% - 12px);padding-top:12px}.mast{display:grid}.demo{padding:12px}}
    .panel{padding:18px;border:3px solid var(--ink);background:var(--paper);box-shadow:8px 8px 0 var(--ink)}.stack{display:grid;gap:12px}.row{display:flex;flex-wrap:wrap;gap:8px}.action{min-height:42px;padding:8px 13px;border:3px solid var(--ink);background:var(--paper);font-weight:900}.action.primary,.action.is-active{color:var(--paper);background:var(--ink)}.status{min-height:24px;padding:8px;color:var(--paper);background:var(--ink);font-weight:900}.metric{font-size:clamp(34px,8vw,76px);font-weight:900;letter-spacing:-.08em}.muted{font-weight:600}.chip{padding:5px 8px;border:2px solid var(--ink);font-weight:900}.meter{height:14px;border:3px solid var(--ink)}.meter>i{display:block;height:100%;background:var(--ink)}
    .composition-split{display:grid;grid-template-columns:150px minmax(0,1fr);gap:18px;align-items:start}.split-note{position:sticky;top:20px;display:grid;gap:14px;padding:18px 12px;border-block:3px double var(--accent);font-size:13px;line-height:1.65}.split-note b{font:900 12px/1 ui-monospace,monospace;letter-spacing:.12em}.split-note span{writing-mode:vertical-rl;min-height:120px;color:color-mix(in srgb,var(--ink) 60%,transparent)}.composition-split .demo{min-width:0}@media(max-width:900px){.composition-split{grid-template-columns:1fr}.split-note{position:static;grid-template-columns:auto 1fr}.split-note span{writing-mode:horizontal-tb;min-height:0}}
    .blocker-stage{display:grid;grid-template-columns:minmax(0,1fr) minmax(250px,.65fr);gap:18px;align-items:center;min-height:390px;padding:clamp(24px,6vw,64px);border:1px solid var(--line);border-radius:30px;background:var(--paper)}.blocker-stage h2{grid-column:1;margin:.2em 0;font-size:clamp(34px,7vw,74px)}.blocker-stage p,.blocker-stage>.action{grid-column:1}.blocker-stage>.action{justify-self:start}.blocker-stage ul{grid-column:2;grid-row:1/5;display:grid;gap:8px;margin:0;padding:0;list-style:none}.blocker-stage li{display:flex;justify-content:space-between;gap:12px;padding:15px;border:1px solid var(--line);border-radius:12px}.blocker-stage li span{opacity:.55}.progress-blocker-demo dialog{width:min(470px,calc(100% - 28px));padding:36px;border:0;border-radius:28px;color:var(--ink);background:var(--paper);box-shadow:0 30px 100px #0008;text-align:center}.progress-blocker-demo dialog::backdrop{background:#07110dc7;backdrop-filter:blur(7px)}.blocker-spinner{display:grid;width:92px;aspect-ratio:1;place-items:center;margin:0 auto 20px;border:2px solid var(--line);border-radius:50%}.blocker-spinner i{width:54px;aspect-ratio:1;border:7px solid var(--line);border-top-color:var(--accent);border-radius:50%;animation:blockerSpin .8s linear infinite}.progress-blocker-demo dialog h2{margin:.25em 0}.blocker-progress{height:12px;overflow:hidden;border-radius:999px;background:var(--line)}.blocker-progress i{display:block;width:0;height:100%;background:linear-gradient(90deg,var(--accent),var(--secondary));transition:width .18s}.progress-blocker-demo dialog output{display:block;margin:12px;font-size:28px;font-weight:900}.progress-blocker-demo dialog button{padding:10px 16px;border:1px solid var(--line);border-radius:10px;background:transparent}@keyframes blockerSpin{to{transform:rotate(1turn)}}@media(max-width:650px){.blocker-stage{grid-template-columns:1fr}.blocker-stage h2,.blocker-stage p,.blocker-stage>.action,.blocker-stage ul{grid-column:auto;grid-row:auto}}.workflow-spatial{display:grid;gap:16px}.workflow-spatial>header{display:grid;grid-template-columns:1fr minmax(170px,.35fr) minmax(170px,.35fr);gap:18px;align-items:end;padding-bottom:16px;border-bottom:5px solid var(--ink)}.workflow-spatial h2{margin:.2em 0}.workflow-spatial header label{display:grid;grid-template-columns:1fr auto;gap:7px}.workflow-spatial header input{grid-column:1/-1;width:100%}.spatial-grid{display:grid;grid-template-columns:minmax(0,var(--spatial-width)) 20px minmax(180px,1fr);gap:0;align-items:stretch}.spatial-core{min-width:0;transform:scale(var(--spatial-zoom));transform-origin:top left;transition:transform .2s}.spatial-handle{display:grid;min-height:300px;place-items:center;border:0;border-inline:1px dashed var(--accent);background:color-mix(in srgb,var(--accent) 10%,transparent);cursor:col-resize}.spatial-grid>aside{display:grid;align-content:center;gap:14px;padding:22px;background:color-mix(in srgb,var(--secondary) 14%,var(--paper))}.spatial-grid>aside strong{font-size:clamp(24px,4vw,42px)}@media(max-width:900px){.workflow-spatial>header{grid-template-columns:1fr}.spatial-grid{order:-1;grid-template-columns:1fr}.spatial-handle{min-height:44px;cursor:row-resize}.spatial-core{transform:none}}
  </style>
</head>
<body data-aesthetic="dashboard" data-composition="split-note">
  <main class="page">
    <header class="mast"><div><span class="eyebrow">dashboard / Progress Mask / ADVANCED</span><h1>Approval Action Sheet Progress Blocker</h1><p class="intro">Complete the progress blocker in an approval form scenario: includes real content, interactive controls, clear state feedback, and responsive layout.</p></div><span class="scenario">Approval Action Sheet</span></header>
    <div class="composition-split"><aside class="split-note"><b>CASE 02</b><span>Master the semantic structure, responsive arrangement, keyboard interaction, and state synchronization of progress overlays.</span></aside><section class="demo" aria-label="Approval Action Sheet Progress Overlay Interaction Area"><div id="workflowSpatial" class="workflow-spatial" style="--spatial-width:64%;--spatial-zoom:1"><header><div><span class="eyebrow">Approval form SPATIAL CANVAS</span><h2>Approval Action Sheet Adjustment Console</h2></div><label>Pending share of workload<input id="workflowSpatialWidth" type="range" min="38" max="82" value="64"><output id="workflowSpatialWidthValue">64%</output></label><label>Content Scaling<input id="workflowSpatialZoom" type="range" min="80" max="120" value="100"><output id="workflowSpatialZoomValue">100%</output></label></header><div class="spatial-grid"><section id="workflowCore" class="workflow-core spatial-core"><!-- 11DZ_CORE_START:overlays-feedback-progress-blocker --><section class="progress-blocker-demo"><div class="blocker-stage"><span class="eyebrow">PROGRESS BLOCKER</span><h2>Handle approval task order</h2><p>Show modal progress only after it has been explicitly started; users can cancel at any time.</p><button id="blockerStart" class="action primary" type="button" data-core-bridge="overlays-feedback-progress-blocker">Start processing</button><ul><li>Approval Workflow Board Collaboration<span>Waiting</span></li><li>Approval Action Sheet Progress<span>Waiting</span></li><li>Approval Request Reminder<span>Waiting</span></li></ul></div><dialog id="progressBlocker" aria-labelledby="blockerTitle"><div class="blocker-spinner" aria-hidden="true"><i></i></div><span class="eyebrow">PROCESSING</span><h2 id="blockerTitle">Processing locally</h2><p id="blockerMessage">Preparing data…</p><div class="blocker-progress" role="progressbar" aria-label="Processing Progress" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0"><i id="blockerMeter"></i></div><output id="blockerValue">0%</output><button id="blockerCancel" type="button">Cancel Processing</button></dialog></section><!-- 11DZ_CORE_END --></section><input id="workflowSpatialHandle" class="spatial-handle" type="button" value="↔" aria-label="Drag to adjust the main case preview width"><aside><strong>Approval action sheet open panel</strong><p>Approval action form in progress and completion feedback will reflow with the canvas size.</p><output id="workflowSpatialStatus">Width 64%, zoom 100%</output><input id="workflowSpatialApply" class="action primary" type="button" value="Processed Successfully"></aside></div></div><p id="status" class="status" role="status" aria-live="polite"></p></section></div>
  </main>
  <script>
    'use strict';
    const statusOutput = document.querySelector('#status');
    const announce = message => { statusOutput.textContent = message; };
    /* 11DZ_CORE_SCRIPT_START:overlays-feedback-progress-blocker */
const progressBlocker=document.querySelector('#progressBlocker');const blockerProgress=progressBlocker.querySelector('[role="progressbar"]');const blockerMeter=document.querySelector('#blockerMeter');const blockerValue=document.querySelector('#blockerValue');const blockerMessage=document.querySelector('#blockerMessage');let blockerTimer=0;let blockerCloseTimer=0;let blockerAmount=0;function cancelBlocker(message){clearInterval(blockerTimer);clearTimeout(blockerCloseTimer);blockerTimer=0;blockerCloseTimer=0;if(progressBlocker.open)progressBlocker.close();announce(message);}document.querySelector('#blockerStart').addEventListener('click',()=>{blockerAmount=0;blockerMeter.style.width='0%';blockerValue.textContent='0%';blockerProgress.setAttribute('aria-valuenow','0');blockerMessage.textContent='Preparing data…';progressBlocker.showModal();blockerTimer=setInterval(()=>{blockerAmount=Math.min(100,blockerAmount+10);blockerMeter.style.width=blockerAmount+'%';blockerValue.textContent=blockerAmount+'%';blockerProgress.setAttribute('aria-valuenow',String(blockerAmount));blockerMessage.textContent=blockerAmount<40?'Preparing data…':blockerAmount<80?'App Settings…':'Complete check…';if(blockerAmount===100){clearInterval(blockerTimer);blockerTimer=0;blockerCloseTimer=setTimeout(()=>cancelBlocker('Local processing complete'),350);}},160);});document.querySelector('#blockerCancel').addEventListener('click',()=>cancelBlocker('Processing canceled'));progressBlocker.addEventListener('cancel',event=>{event.preventDefault();cancelBlocker('Processing canceled');});
/* 11DZ_CORE_SCRIPT_END */
const workflowBridgeSpec={"name":"overlays-feedback-progress-blocker","selector":"[data-core-bridge=\"overlays-feedback-progress-blocker\"]","mode":"click","key":"Enter"};const workflowBridgeCore=document.querySelector('#workflowCore');const workflowBridgeControl=workflowBridgeCore.querySelector(workflowBridgeSpec.selector);if(!workflowBridgeControl)throw new Error('Missing core bridge: '+workflowBridgeSpec.name);const workflowBridgeControlledId=workflowBridgeControl.getAttribute('aria-controls');const workflowBridgeControlled=workflowBridgeControlledId?document.getElementById(workflowBridgeControlledId):null;workflowBridgeCore.dataset.workflowBridge=workflowBridgeSpec.name;workflowBridgeCore.dataset.workflowVersion='0';function workflowBridgeSerialize(){const visualNode=workflowBridgeCore.firstElementChild||workflowBridgeCore;const visual=getComputedStyle(visualNode);const outputs=[...workflowBridgeCore.querySelectorAll('output,[role="status"],[aria-live],meter,progress')].map(node=>node.textContent.trim()+'|'+node.getAttribute('aria-valuenow')+'|'+node.getAttribute('value'));const canvas=[...workflowBridgeCore.querySelectorAll('canvas')].map(node=>{try{return node.toDataURL().slice(-160);}catch{return 'canvas-unavailable';}});return JSON.stringify({html:workflowBridgeCore.innerHTML,status:statusOutput.textContent,outputs,canvas,visual:[visual.display,visual.visibility,visual.opacity,visual.transform,visual.filter,visual.backgroundColor,visual.width,visual.height],scroll:workflowBridgeSpec.mode==='scroll'?workflowBridgeControl.scrollTop:null});}let workflowBridgeLastEffect=workflowBridgeSerialize();function workflowBridgeSummary(){const label=(workflowBridgeControl.getAttribute('aria-label')||workflowBridgeControl.textContent||workflowBridgeControl.value||workflowBridgeSpec.name).trim().replace(/\s+/g,' ').slice(0,72);return label+' · Core Version '+workflowBridgeCore.dataset.workflowVersion;}function workflowBridgeCommit(){const effect=workflowBridgeSerialize();if(effect===workflowBridgeLastEffect)return {changed:false,summary:workflowBridgeSummary()};workflowBridgeLastEffect=effect;workflowBridgeCore.dataset.workflowVersion=String(Number(workflowBridgeCore.dataset.workflowVersion||0)+1);return {changed:true,summary:workflowBridgeSummary()};}function workflowBridgeScheduleCommit(){queueMicrotask(workflowBridgeCommit);setTimeout(workflowBridgeCommit,0);}workflowBridgeControl.addEventListener("click",workflowBridgeScheduleCommit);const workflowBridgeStateTargets=new Set(workflowBridgeCore.querySelectorAll('dialog'));if(workflowBridgeControlled&&workflowBridgeCore.contains(workflowBridgeControlled))workflowBridgeStateTargets.add(workflowBridgeControlled);workflowBridgeStateTargets.forEach(target=>['close','cancel','toggle'].forEach(eventName=>target.addEventListener(eventName,workflowBridgeScheduleCommit)));function workflowBridgeActivate(){workflowBridgeControl.focus();workflowBridgeControl.click();const result=workflowBridgeCommit();setTimeout(workflowBridgeCommit,0);return result;}function workflowBridgeReset(){workflowBridgeCore.dataset.workflowVersion='0';workflowBridgeLastEffect=workflowBridgeSerialize();}
const workflowSpatial=document.querySelector('#workflowSpatial');const workflowSpatialCore=document.querySelector('#workflowCore');const workflowSpatialWidth=document.querySelector('#workflowSpatialWidth');const workflowSpatialZoom=document.querySelector('#workflowSpatialZoom');const workflowSpatialHandle=document.querySelector('#workflowSpatialHandle');const workflowSpatialState={width:64,zoom:1,dragging:false};function workflowSpatialDrive(){workflowSpatial.style.setProperty('--spatial-width',workflowSpatialState.width+'%');workflowSpatial.style.setProperty('--spatial-zoom',String(workflowSpatialState.zoom));workflowSpatialWidth.value=String(workflowSpatialState.width);workflowSpatialZoom.value=String(Math.round(workflowSpatialState.zoom*100));document.querySelector('#workflowSpatialWidthValue').textContent=workflowSpatialState.width+'%';document.querySelector('#workflowSpatialZoomValue').textContent=Math.round(workflowSpatialState.zoom*100)+'%';document.querySelector('#workflowSpatialStatus').textContent='width '+workflowSpatialState.width+'%, zoom '+Math.round(workflowSpatialState.zoom*100)+'%';announce('Approval action sheet canvas has been rearranged');}workflowSpatialWidth.addEventListener('input',()=>{workflowSpatialState.width=Number(workflowSpatialWidth.value);workflowSpatialDrive();});workflowSpatialZoom.addEventListener('input',()=>{workflowSpatialState.zoom=Number(workflowSpatialZoom.value)/100;workflowSpatialDrive();});workflowSpatialHandle.addEventListener('pointerdown',event=>{workflowSpatialState.dragging=true;workflowSpatialHandle.setPointerCapture(event.pointerId);});workflowSpatialHandle.addEventListener('pointermove',event=>{if(!workflowSpatialState.dragging)return;const rect=workflowSpatial.getBoundingClientRect();workflowSpatialState.width=Math.max(38,Math.min(82,Math.round((event.clientX-rect.left)/rect.width*100)));workflowSpatialDrive();});workflowSpatialHandle.addEventListener('pointerup',event=>{workflowSpatialState.dragging=false;workflowSpatialHandle.releasePointerCapture(event.pointerId);});workflowSpatialHandle.addEventListener('wheel',event=>{event.preventDefault();workflowSpatialState.zoom=Math.max(.8,Math.min(1.2,workflowSpatialState.zoom+(event.deltaY<0?.05:-.05)));workflowSpatialDrive();},{passive:false});workflowSpatialHandle.addEventListener('keydown',event=>{if(!['ArrowLeft','ArrowRight'].includes(event.key))return;event.preventDefault();workflowSpatialState.width=Math.max(38,Math.min(82,workflowSpatialState.width+(event.key==='ArrowRight'?2:-2)));workflowSpatialDrive();});document.querySelector('#workflowSpatialApply').addEventListener('click',()=>{const bridge=workflowBridgeActivate();document.querySelector('#workflowSpatialStatus').textContent='Processed · width '+workflowSpatialState.width+'%, zoom '+Math.round(workflowSpatialState.zoom*100)+'% · '+bridge.summary;announce(document.querySelector('#workflowSpatialStatus').textContent);});workflowSpatialDrive();
workflowBridgeReset();
  </script>
</body>
</html>
Page feedbackFound an issue or have suggestions for improvement?
Feedback features need to be used in the online version

Please enable JavaScript in the online version before submitting; local features of the current tool or example are not affected.

Go to the online version for feedback