progress-bar-with-steps
Version:
Scalable, pure CSS progress bar with a variable number of steps and a customizable color palette
2 lines (1 loc) • 4 kB
JavaScript
function stepsBarFragment(e){const t=document.createElement("div");return t.className="steps-bar-fragment",t.classList.toggle("completed",e),t}function stepsBarCircle(e,t){const r=document.createElement("div");r.className="steps-bar-circle-wrapper";const n=document.createElement("div");n.className="steps-bar-circle",n.classList.toggle("current",e),r.appendChild(n);const s=document.createElement("p");return s.innerText=t||"",r.appendChild(s),r}function createCSS(){let e=document.createElement("style");e.innerHTML="\n /* Style rules for progress bar with steps */\n .steps-bar {\n position: relative;\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: center;\n }\n \n .steps-bar-fragment {\n /* take up extra space in div */\n flex-grow: 1;\n }\n \n .steps-bar-circle {\n /* center circle in middle of div (right on top of progress bar) */\n position: absolute;\n top: 50%;\n transform: translateY(-50%);\n }\n \n .steps-bar-circle-wrapper {\n /* 1px width on the wrapper with visible overflow so the left and right proress bar\n fragments will go under the circle */\n max-width: 1px;\n overflow: visible;\n z-index: 5;\n display: flex;\n\n flex-direction: column;\n align-items: center;\n }\n\n /* Label */\n .steps-bar-circle-wrapper > p {\n position: absolute;\n margin-bottom: 0;\n text-align: center;\n word-break: break-all;\n /* Lock to bottom of the div */\n bottom: 0;\n }",document.getElementsByTagName("head")[0].appendChild(e)}function createInlineStyles(e){const t=e.dataset.incompleteColor,r=parseInt(e.dataset.numSteps),n=e.dataset.completeColorPrimary,s=e.dataset.completeColorSecondary,a=e.dataset.circlePrimary,l=e.dataset.circleSecondary,o=parseFloat(e.dataset.animationDuration),i=e.dataset.textColor,c=e.dataset.barBorder,d=e.dataset.scale,m=e.dataset.key;e.style.height=""+(d?6*d+"rem":"6rem");let p=document.createElement("style");p.innerHTML=`\n @keyframes steps-bar-gradient-${m} {\n 0% { background-color: ${n||"#227b81"}; }\n 50% { background-color: ${s||"#8EDBE1"}; }\n 100% { background-color: ${n||"#227b81"}; }\n };`,document.getElementsByTagName("head")[0].appendChild(p),e.querySelectorAll(".steps-bar-fragment").forEach((r=>{r===e.firstElementChild&&(r.style.borderRadius=`${d?.5*d+"rem":"0.5rem"} 0px 0px ${d?.5*d+"rem":"0.5rem"}`),r===e.lastElementChild&&(r.style.borderRadius=`0px ${d?.5*d+"rem":"0.5rem"} ${d?.5*d+"rem":"0.5rem"} 0px`),r.classList.contains("completed")&&(r.style.animation=`steps-bar-gradient-${m} ${o?o+"s":"6s"} linear infinite`),r.style.height=d?.5*d+"rem":"0.5rem",r.style.backgroundColor=t||"#ffffff",r.style.border=c?`3px solid ${c}`:"none"}));let f=e.querySelectorAll(".steps-bar-circle-wrapper > p"),u=1/(r+1)*100;f.forEach((e=>{e.style.color=`${i||"#000000"}`,e.style.fontSize=""+(d?d+"rem":"1rem"),e.style.height=""+(d?d+"rem":"1rem"),e.style.width=`${u||"20"}%`})),e.querySelectorAll(".steps-bar-circle").forEach((e=>{e.classList.contains("current")?(e.style.minWidth=""+(d?3*d+"rem":"3rem"),e.style.minHeight=""+(d?3*d+"rem":"3rem"),e.style.borderRadius=""+(d?1.5*d+"rem":"1.5rem"),e.style.backgroundColor=`${l||"#8EDBE1"}`,e.style.border=`3px solid ${a||"#ffffff"}`):(e.style.minWidth=""+(d?2*d+"rem":"2rem"),e.style.minHeight=""+(d?2*d+"rem":"2rem"),e.style.borderRadius=""+(d?d+"rem":"1rem"),e.style.backgroundColor=`${a||"#ffffff"}`,e.style.border=`3px solid ${l||"#8EDBE1"}`)}))}function initProgressBars(){createCSS();document.querySelectorAll(".steps-bar").forEach((e=>{const t=parseInt(e.dataset.numSteps),r=parseInt(e.dataset.currentStep),n=JSON.parse(e.dataset.complete);e.appendChild(stepsBarFragment(!0));for(let s=0;s<t;s++){const a=e.dataset[`labelText-${s+1}`];e.appendChild(stepsBarCircle(s===r-1,a,t)),e.appendChild(stepsBarFragment(s<r-1||n))}createInlineStyles(e)}))}"undefined"!=typeof module&&module.exports&&(module.exports={initProgressBars:initProgressBars});