About this Code
Hello reader, I am jkantner. Nice to meet you again in this free code sharing website. In this post I am going to explain about Step indicator.
If you are new to this website, we recommend you to subscribe to our youtube channel and watch the videos. Ok lets dive into the code.
Images
These are the output images of the code. You can click on the image to enlarge it. also you can click the try it button to see the output.
Youtube Tutorial Video
If you are a visual learner and want to learn how to use this code, you can watch the video below.
and also this video contains the clear step by step explanation and the output of the code.
VIDEO
Source Code
This is the source code of the code. You can copy and paste the code to your editor.
@charset "UTF-8";
@import url(https://fonts.googleapis.com/css?family=Nunito+Sans:300,400,600,700,800);
*,
:after,
:before {
box-sizing: border-box;
padding: 0;
margin: 0;
}
* {
border: 0;
box-sizing: border-box;
margin: 0;
padding: 0;
}
:root {
--hue: 223;
--bg: hsl(var(--hue),10%,90%);
--fg: hsl(var(--hue),10%,10%);
--primary: hsl(var(--hue),90%,30%);
--trans-dur: 0.3s;
--trans-timing: cubic-bezier(0.65,0,0.35,1);
font-size: calc(16px + (48 - 16) * (100vw - 280px) / (3840 - 280));
}
body,
button {
font: 1em/1.5 "DM Sans", sans-serif;
}
body {
background-color: var(--bg);
color: var(--fg);
display: flex;
height: 100vh;
}
form {
container: form / inline-size;
margin: auto;
padding: 1.5em;
width: 100%;
max-width: 36em;
}
.btn {
background-color: var(--primary);
border-radius: 0.25em;
color: hsl(0,0%,100%);
cursor: pointer;
display: block;
padding: 0.375em 0.75em;
transition:
background-color var(--trans-dur) var(--trans-timing),
opacity var(--trans-dur) var(--trans-timing);
width: 100%;
-webkit-appearance: none;
appearance: none;
-webkit-tap-highlight-color: transparent;
&:disabled {
cursor: not-allowed;
opacity: 0.5;
}
&:not(:disabled):hover {
background: hsl(var(--hue),90%,10%);
}
&-group {
display: flex;
justify-content: center;
gap: 0.75em;
margin-top: 1.5em;
}
}
.steps {
// --trans-dur: 0.15s;
background-color: hsl(0,0%,100%);
border-radius: 0.75em;
display: flex;
padding: 1.5em;
flex-direction: column;
justify-content: center;
width: 100%;
&__connector,
&__step {
position: relative;
}
&__connector {
background-color: hsl(var(--hue),10%,80%);
margin-inline-start: 0.75em;
width: 0.125em;
height: 1.25em;
transform: translateX(-50%);
transition: background-color var(--trans-dur);
&:before {
background-color: var(--primary);
content: "";
display: block;
width: 100%;
height: 100%;
transform: scale(1,0);
transform-origin: 50% 0;
transition:
background-color var(--trans-dur),
transform var(--trans-dur) var(--trans-timing);
}
}
&__step {
display: flex;
align-items: center;
flex-shrink: 0;
z-index: 1;
&-name {
color: hsl(var(--hue),10%,50%);
font-size: 0.75em;
line-height: 2;
transition:
color var(--trans-dur) var(--trans-timing),
font-weight var(--trans-dur) var(--trans-timing);
}
&-number {
background-color: hsl(var(--hue),10%,80%);
color: hsl(0,0%,100%);
border-radius: 50%;
margin-inline-end: 0.5em;
text-align: center;
width: 1.5em;
height: 1.5em;
transition:
background-color var(--trans-dur) var(--trans-timing),
box-shadow var(--trans-dur) var(--trans-timing);
}
&--current &-name,
&--done &-name {
color: hsl(var(--hue),10%,10%);
font-weight: 700;
}
&--current &-number,
&--done &-number {
background-color: var(--primary);
}
&--current &-number,
&--current &-name {
transition-delay: var(--trans-dur);
}
&--current &-number {
box-shadow: 0 0 0 0.125em hsla(var(--hue),90%,30%,0.4);
}
}
&__step--done + &__connector {
&:before {
transform: scale(1,1);
}
}
}
/* Change layout depending on form width */
@container form (min-width: 30em) {
.btn {
width: auto;
}
.steps {
flex-direction: row;
align-items: center;
padding: 1.5em 2.25em 2.25em 2.25em;
&__connector {
margin-inline-start: 0;
width: 100%;
height: 0.125em;
transform: translateY(-50%);
&:before {
transform: scale(0,1);
transform-origin: 0 50%;
[dir="rtl"] & {
transform-origin: 100% 50%;
}
}
}
&__step {
&-name {
position: absolute;
top: 100%;
left: 50%;
text-align: center;
width: 6em;
transform: translateX(-50%);
}
&-number {
margin-inline-end: 0;
}
}
}
}
/* Dark theme */
@media (prefers-color-scheme: dark) {
:root {
--bg: hsl(var(--hue),10%,10%);
--fg: hsl(var(--hue),10%,90%);
--primary: hsl(var(--hue),90%,70%);
}
.btn {
color: hsl(var(--hue),10%,10%);
&:not(:disabled):hover {
background: hsl(var(--hue),90%,50%);
}
}
.steps {
background-color: hsl(var(--hue),10%,20%);
&__connector {
background-color: hsl(var(--hue),10%,40%);
}
&__step {
&-name {
color: hsl(var(--hue),10%,50%);
}
&-number {
background-color: hsl(var(--hue),10%,40%);
color: hsl(var(--hue),10%,20%);
}
&--current &-name,
&--done &-name {
color: hsl(var(--hue),10%,90%);
}
&--current &-number {
box-shadow: 0 0 0 0.125em hsla(var(--hue),90%,70%,0.4);
}
}
}
}
console.log("Event Fired")
window.addEventListener("DOMContentLoaded",() => {
const steps = new StepIndicator(".steps");
});
class StepIndicator {
/** Element used for this step indicator. */
el: HTMLElement | null;
/** Number of steps */
steps = 5;
private _step = 0;
get step(): number {
return this._step;
}
set step(value: number) {
this.displayStep(value);
this._step = value;
this.checkExtremes();
}
/**
* @param el CSS selector of the step indicator element
*/
constructor(el: string) {
this.el = document.querySelector(el);
document.addEventListener("click",this.clickAction.bind(this));
this.displayStep(this.step);
this.checkExtremes();
}
/**
* @param e Click event
*/
clickAction(e: Event): void {
const button = e.target as HTMLButtonElement;
const actionName = button?.getAttribute("data-action");
if (actionName === "prev") {
this.prev();
} else if (actionName === "next") {
this.next();
}
}
/** Go to the previous step. */
prev(): void {
if (this.step > 0) {
--this.step;
}
}
/** Go to the next step. */
next(): void {
if (this.step < this.steps - 1) {
++this.step;
}
}
/** Disable the Previous or Next button if hitting the first or last step. */
checkExtremes(): void {
const prevBtnEl = document.querySelector(`[data-action="prev"]`) as HTMLButtonElement;
const nextBtnEl = document.querySelector(`[data-action="next"]`) as HTMLButtonElement;
if (prevBtnEl) {
prevBtnEl.disabled = this.step <= 0;
}
if (nextBtnEl) {
nextBtnEl.disabled = this.step >= this.steps - 1;
}
}
/**
* Update the indicator for a targeted step.
* @param targetStep Index of the step
*/
displayStep(targetStep: number) {
const current = "steps__step--current";
const done = "steps__step--done";
for (let s = 0; s < this.steps; ++s) {
const stepEl = this.el?.querySelector(`[data-step="${s}"]`);
stepEl?.classList.remove(current,done);
if (s < targetStep) {
stepEl?.classList.add(done);
} else if (s === targetStep) {
stepEl?.classList.add(current);
}
}
}
}
And also you can click the try it button to see the output of the code in our web Code Playground.
You can also download the code to the zip format by clicking the download button. The download process is little bit complex, you need ti await for 10 seconds. after that you can download the code by clicking the generated download link.
Leave a Comment
You need to login first to comment.