Author: | nat-davydova |
---|---|
Views Total: | 53,182 views |
Official Page: | Go to website |
Last Update: | October 2, 2019 |
License: | MIT |
Preview:

Description:
A JavaScript and CSS extension of Bootstrap 4 that lets you create a multi-step form with custom CSS3 animations.
Without the need of jQuery library and Bootstrap JS.
How to use it:
Include the Bootstrap’s stylesheet on the page.
<script src="/path/to/bootstrap.min.css"></script>
Add form panels together with a progress bar to the multi-step form as shown below:
<div class="multisteps-form"> <!--progress bar--> <div class="row"> <div class="col-12 col-lg-8 ml-auto mr-auto mb-4"> <div class="multisteps-form__progress"> <button class="multisteps-form__progress-btn js-active" type="button" title="User Info">User Info</button> <button class="multisteps-form__progress-btn" type="button" title="Address">Address</button> <button class="multisteps-form__progress-btn" type="button" title="Order Info">Order Info</button> <button class="multisteps-form__progress-btn" type="button" title="Comments">Comments </button> </div> </div> </div> <!--form panels--> <div class="row"> <div class="col-12 col-lg-8 m-auto"> <form class="multisteps-form__form"> <!--single form panel--> <div class="multisteps-form__panel shadow p-4 rounded bg-white js-active" data-animation="scaleIn"> <h3 class="multisteps-form__title">Your User Info</h3> <div class="multisteps-form__content"> <div class="form-row mt-4"> <div class="col-12 col-sm-6"> <input class="multisteps-form__input form-control" type="text" placeholder="First Name"/> </div> <div class="col-12 col-sm-6 mt-4 mt-sm-0"> <input class="multisteps-form__input form-control" type="text" placeholder="Last Name"/> </div> </div> <div class="form-row mt-4"> <div class="col-12 col-sm-6"> <input class="multisteps-form__input form-control" type="text" placeholder="Login"/> </div> <div class="col-12 col-sm-6 mt-4 mt-sm-0"> <input class="multisteps-form__input form-control" type="email" placeholder="Email"/> </div> </div> <div class="form-row mt-4"> <div class="col-12 col-sm-6"> <input class="multisteps-form__input form-control" type="password" placeholder="Password"/> </div> <div class="col-12 col-sm-6 mt-4 mt-sm-0"> <input class="multisteps-form__input form-control" type="password" placeholder="Repeat Password"/> </div> </div> <div class="button-row d-flex mt-4"> <button class="btn btn-primary ml-auto js-btn-next" type="button" title="Next">Next</button> </div> </div> </div> <!--single form panel--> <div class="multisteps-form__panel shadow p-4 rounded bg-white" data-animation="scaleIn"> <h3 class="multisteps-form__title">Your Address</h3> <div class="multisteps-form__content"> <div class="form-row mt-4"> <div class="col"> <input class="multisteps-form__input form-control" type="text" placeholder="Address 1"/> </div> </div> <div class="form-row mt-4"> <div class="col"> <input class="multisteps-form__input form-control" type="text" placeholder="Address 2"/> </div> </div> <div class="form-row mt-4"> <div class="col-12 col-sm-6"> <input class="multisteps-form__input form-control" type="text" placeholder="City"/> </div> <div class="col-6 col-sm-3 mt-4 mt-sm-0"> <select class="multisteps-form__select form-control"> <option selected="selected">State...</option> <option>...</option> </select> </div> <div class="col-6 col-sm-3 mt-4 mt-sm-0"> <input class="multisteps-form__input form-control" type="text" placeholder="Zip"/> </div> </div> <div class="button-row d-flex mt-4"> <button class="btn btn-primary js-btn-prev" type="button" title="Prev">Prev</button> <button class="btn btn-primary ml-auto js-btn-next" type="button" title="Next">Next</button> </div> </div> </div> <!--single form panel--> <div class="multisteps-form__panel shadow p-4 rounded bg-white" data-animation="scaleIn"> <h3 class="multisteps-form__title">Your Order Info</h3> <div class="multisteps-form__content"> <div class="row"> <div class="col-12 col-md-6 mt-4"> <div class="card shadow-sm"> <div class="card-body"> <h5 class="card-title">Item Title</h5> <p class="card-text">Small and nice item description</p><a class="btn btn-primary" href="#" title="Item Link">Item Link</a> </div> </div> </div> <div class="col-12 col-md-6 mt-4"> <div class="card shadow-sm"> <div class="card-body"> <h5 class="card-title">Item Title</h5> <p class="card-text">Small and nice item description</p><a class="btn btn-primary" href="#" title="Item Link">Item Link</a> </div> </div> </div> </div> <div class="row"> <div class="button-row d-flex mt-4 col-12"> <button class="btn btn-primary js-btn-prev" type="button" title="Prev">Prev</button> <button class="btn btn-primary ml-auto js-btn-next" type="button" title="Next">Next</button> </div> </div> </div> </div> <!--single form panel--> <div class="multisteps-form__panel shadow p-4 rounded bg-white" data-animation="scaleIn"> <h3 class="multisteps-form__title">Additional Comments</h3> <div class="multisteps-form__content"> <div class="form-row mt-4"> <textarea class="multisteps-form__textarea form-control" placeholder="Additional Comments and Requirements"></textarea> </div> <div class="button-row d-flex mt-4"> <button class="btn btn-primary js-btn-prev" type="button" title="Prev">Prev</button> <button class="btn btn-success ml-auto" type="button" title="Send">Send</button> </div> </div> </div> </form> </div> </div> </div>
The necessary CSS styles for the multi-step form.
.multisteps-form__progress { display: grid; grid-template-columns: repeat(auto-fit, minmax(0, 1fr)); } .multisteps-form__progress-btn { transition-property: all; transition-duration: 0.15s; transition-timing-function: linear; transition-delay: 0s; position: relative; padding-top: 20px; color: rgba(108, 117, 125, 0.7); text-indent: -9999px; border: none; background-color: transparent; outline: none !important; cursor: pointer; } @media (min-width: 500px) { .multisteps-form__progress-btn { text-indent: 0; } } .multisteps-form__progress-btn:before { position: absolute; top: 0; left: 50%; display: block; width: 13px; height: 13px; content: ''; -webkit-transform: translateX(-50%); transform: translateX(-50%); transition: all 0.15s linear 0s, -webkit-transform 0.15s cubic-bezier(0.05, 1.09, 0.16, 1.4) 0s; transition: all 0.15s linear 0s, transform 0.15s cubic-bezier(0.05, 1.09, 0.16, 1.4) 0s; transition: all 0.15s linear 0s, transform 0.15s cubic-bezier(0.05, 1.09, 0.16, 1.4) 0s, -webkit-transform 0.15s cubic-bezier(0.05, 1.09, 0.16, 1.4) 0s; border: 2px solid currentColor; border-radius: 50%; background-color: #fff; box-sizing: border-box; z-index: 3; } .multisteps-form__progress-btn:after { position: absolute; top: 5px; left: calc(-50% - 13px / 2); transition-property: all; transition-duration: 0.15s; transition-timing-function: linear; transition-delay: 0s; display: block; width: 100%; height: 2px; content: ''; background-color: currentColor; z-index: 1; } .multisteps-form__progress-btn:first-child:after { display: none; } .multisteps-form__progress-btn.js-active { color: #007bff; } .multisteps-form__progress-btn.js-active:before { -webkit-transform: translateX(-50%) scale(1.2); transform: translateX(-50%) scale(1.2); background-color: currentColor; } .multisteps-form__form { position: relative; } .multisteps-form__panel { position: absolute; top: 0; left: 0; width: 100%; height: 0; opacity: 0; visibility: hidden; } .multisteps-form__panel.js-active { height: auto; opacity: 1; visibility: visible; }
Define your own CSS3 animations in the CSS.
.multisteps-form__panel[data-animation="scaleIn"] { -webkit-transform: scale(0.9); transform: scale(0.9); } .multisteps-form__panel[data-animation="scaleIn"].js-active { transition-property: all; transition-duration: 0.2s; transition-timing-function: linear; transition-delay: 0s; -webkit-transform: scale(1); transform: scale(1); }
The main JavaScript to activate the multi-step form.
//DOM elements const DOMstrings = { stepsBtnClass: 'multisteps-form__progress-btn', stepsBtns: document.querySelectorAll(`.multisteps-form__progress-btn`), stepsBar: document.querySelector('.multisteps-form__progress'), stepsForm: document.querySelector('.multisteps-form__form'), stepsFormTextareas: document.querySelectorAll('.multisteps-form__textarea'), stepFormPanelClass: 'multisteps-form__panel', stepFormPanels: document.querySelectorAll('.multisteps-form__panel'), stepPrevBtnClass: 'js-btn-prev', stepNextBtnClass: 'js-btn-next' }; //remove class from a set of items const removeClasses = (elemSet, className) => { elemSet.forEach(elem => { elem.classList.remove(className); }); }; //return exect parent node of the element const findParent = (elem, parentClass) => { let currentNode = elem; while (!currentNode.classList.contains(parentClass)) { currentNode = currentNode.parentNode; } return currentNode; }; //get active button step number const getActiveStep = elem => { return Array.from(DOMstrings.stepsBtns).indexOf(elem); }; //set all steps before clicked (and clicked too) to active const setActiveStep = activeStepNum => { //remove active state from all the state removeClasses(DOMstrings.stepsBtns, 'js-active'); //set picked items to active DOMstrings.stepsBtns.forEach((elem, index) => { if (index <= activeStepNum) { elem.classList.add('js-active'); } }); }; //get active panel const getActivePanel = () => { let activePanel; DOMstrings.stepFormPanels.forEach(elem => { if (elem.classList.contains('js-active')) { activePanel = elem; } }); return activePanel; }; //open active panel (and close unactive panels) const setActivePanel = activePanelNum => { //remove active class from all the panels removeClasses(DOMstrings.stepFormPanels, 'js-active'); //show active panel DOMstrings.stepFormPanels.forEach((elem, index) => { if (index === activePanelNum) { elem.classList.add('js-active'); setFormHeight(elem); } }); }; //set form height equal to current panel height const formHeight = activePanel => { const activePanelHeight = activePanel.offsetHeight; DOMstrings.stepsForm.style.height = `${activePanelHeight}px`; }; const setFormHeight = () => { const activePanel = getActivePanel(); formHeight(activePanel); }; //STEPS BAR CLICK FUNCTION DOMstrings.stepsBar.addEventListener('click', e => { //check if click target is a step button const eventTarget = e.target; if (!eventTarget.classList.contains(`${DOMstrings.stepsBtnClass}`)) { return; } //get active button step number const activeStep = getActiveStep(eventTarget); //set all steps before clicked (and clicked too) to active setActiveStep(activeStep); //open active panel setActivePanel(activeStep); }); //PREV/NEXT BTNS CLICK DOMstrings.stepsForm.addEventListener('click', e => { const eventTarget = e.target; //check if we clicked on `PREV` or NEXT` buttons if (!(eventTarget.classList.contains(`${DOMstrings.stepPrevBtnClass}`) || eventTarget.classList.contains(`${DOMstrings.stepNextBtnClass}`))) { return; } //find active panel const activePanel = findParent(eventTarget, `${DOMstrings.stepFormPanelClass}`); let activePanelNum = Array.from(DOMstrings.stepFormPanels).indexOf(activePanel); //set active step and active panel onclick if (eventTarget.classList.contains(`${DOMstrings.stepPrevBtnClass}`)) { activePanelNum--; } else { activePanelNum++; } setActiveStep(activePanelNum); setActivePanel(activePanelNum); }); //SETTING PROPER FORM HEIGHT ONLOAD window.addEventListener('load', setFormHeight, false); //SETTING PROPER FORM HEIGHT ONRESIZE window.addEventListener('resize', setFormHeight, false);
Hey! How can make more steps in here ?
validation?