GETTING STARTED
A stepper is a fundamental part of material design guidelines. It makes forms simplier and a lot of other stuffs.
Unfortunately, one of the best material design front-end frameworks we have today, Materilizecss, doesn't have an implemented stepper. So I decided to create one.
Here you going to find some demos and some code, but you can find the full documentation on GitHub.
I hope you like and help me improve it.
PREREQUISITES
Since it's an implementation to Materializecss framework, you'll need it:
- Materializecss framework
- Google Material Icons
INSTALLING
Direct download
-
CSS:
- mstepper.min.css minified, or
- mstepper.css un-minified
-
JavaScript:
- mstepper.min.js minified, or
- mstepper.js un-minified
NPM
npm install --save materialize-stepper
YARN
yarn add materialize-stepper
CDN
<!-- CSS -->
<link rel="stylesheet" href="https://unpkg.com/materialize-stepper@3.1.0/dist/css/mstepper.min.css">
<!-- JS -->
<script src="https://unpkg.com/materialize-stepper@3.1.0/dist/js/mstepper.min.js">
Demos
Linear Stepper
Linear Stepper is the most common one. In it, you can't navigate freely between steps. It's step by step, obeying the validation function.
Example:
<ul class="stepper linear">...</ul>
-
Step 1
-
Step 2
-
Step 3Finish!
Non-linear Stepper
In the Non-Linear Stepper you can navigate freely between steps. You can also use the buttons for validation, but if the user wants to move arbitrarily around the steps, it's allowed by clicking on the steps instead of the buttons.
Example:
<ul class="stepper">...</ul>
-
Step 1
-
Step 2
-
Step 3Finish!
Feedback Stepper
If you want, for example, to check if an e-mail exists in your DB, you can define a feedback function with data-feedback attribute in your next button.
When the user try to move forward, a loading screen will overlay the active step until you run destroyFeedback(true) (first param received by the function) with "true" in the first parameter to also skip the step (instead of just destroy the feedback preloader).
Example:
<button class="waves-effect waves-dark btn next-step" data-feedback="someFunction">CONTINUE</button>
<script>
function someFunction(destroyFeedback) {
// Do your stuff here
// Call destroyFeedback() function when you're done
// The true parameter will proceed to the next step besides destroying the preloader
setTimeout(() => {
destroyFeedback(true);
}, 1000);
}
</script>
-
Step 1
-
Step 2
-
Step 3Finish!
Horizontal Stepper
There is a horizontal version now (since 2.0). All the options above listed is working with it. And since version 2.1 horizontal steppers are responsive and turns to vertical from 992px (width) down:
To use it, you just need to add a ".horizontal" class to your primary "ul" tag:
Example:
<ul class="stepper horizontal">
...
</ul>
-
Step 1
-
Step 2
-
Step 3Finish!
USAGE
The HTML base is like this:
<ul class="stepper linear">
<li class="step active">
<div class="step-title waves-effect">E-mail</div>
<div class="step-content">
<!-- Your step content goes here (like inputs or so) -->
<div class="step-actions">
<!-- Here goes your actions buttons -->
<button class="waves-effect waves-dark btn next-step">CONTINUE</button>
</div>
</div>
</li>
</ul>
After that you'll need to initialize it through:
<script>
var stepper = document.querySelector('.stepper');
var stepperInstace = new MStepper(stepper, {
// options
firstActive: 0 // this is the default
})
</script>
EXPLANATION
Every class explains very well it's function, so... Everything runs inside a ul with ".stepper" class:
<ul class="stepper linear">...</ul>
Each step runs inside a li tag with the class ".step":
<li class="step">...</li>
Inside each step there is two divs. The ".step-title", where you put the title of... guess what...
<div class="step-title waves-effect waves-dark">First step</div>
And the ".step-content", that holds the information:
<div class="step-content">...</div>
There's the ".step-actions" container inside step-content, which holds the buttons:
<div class="step-actions"></div>
And finally there's the buttons, which proceed (.next-step) or return (.previous-step):
<button class="waves-effect waves-dark btn next-step">CONTINUE</button>
<button class="waves-effect waves-dark btn-flat previous-step">BACK</button>
OPTIONS
JS initialization setting(s)
If you are using linear stepper, clicking on the next and the previous step will work just like the buttons. Since 2.1 you can adjust some options. Here they are, with their respective defaults:
var stepper = document.querySelector('.stepper');
var stepperInstace = new MStepper(stepper, {
// Default active step.
firstActive: 0,
// Allow navigation by clicking on the next and previous steps on linear steppers.
linearStepsNavigation: true,
// Auto focus on first input of each step.
autoFocusInput: false,
// Set if a loading screen will appear while feedbacks functions are running.
showFeedbackPreloader: true,
// Auto generation of a form around the stepper.
autoFormCreation: true,
// Function to be called everytime a nextstep occurs. It receives 2 arguments, in this sequece: stepperForm, activeStepContent.
validationFunction: defaultValidationFunction, // more about this default functions below
// Enable or disable navigation by clicking on step-titles
stepTitleNavigation: true,
// Preloader used when step is waiting for feedback function. If not defined, Materializecss spinner-blue-only will be used.
feedbackPreloader: '<div class="spinner-layer spinner-blue-only">...</div>'
})
Form validation
As described in the previous topic, you can define a validation function to be called on every nextStep() in the stepper init options.
This function will be called with two parameters:
function validationFunction(stepperForm, activeStepContent) {
// You can use the 'stepperForm' to valide the whole form around the stepper:
someValidationPlugin(stepperForm);
// Or you can do something with just the activeStepContent
someValidationPlugin(activeStepContent);
// Return true or false to proceed or show an error
return true;
}
If you don't define anything, a default validation function will be used. This default function is the defaultValidationFunction. It's a simple form validation that works like this:
defaultValidationFunction(stepperForm, activeStepContent) {
var inputs = activeStepContent.querySelectorAll('input, textarea, select');
for (let i = 0; i < inputs.length; i++) if (!inputs[i].checkValidity()) return false;
return true;
}
Horizontal and vertical
You can make your stepper horizontal just adding a ".horizontal" class to your primary "ul" tag. Since version 2.1 horizontal steppers are responsive and turns to vertical from 992px (width) down:
<ul class="stepper horizontal">...</ul>
For now, horizontal stepper contents doesn't have an automatic height. You can change the default size (458px) of your primary "ul" class with CSS:
ul.stepper.horizontal {
min-height: 458px;
}
or inline:
<ul class="stepper horizontal" style="min-height:458px">...</ul>
IMPORTANT: THE HEIGHT OF THE ".stepper-content" TAG IS SUBTRACTED BY 84PX. SO, FOR EXAMPLE, IF YOU WANT YOUR CONTENT TO HAVE 400PX HEIGHT, YOU'LL NEED TO SET THE "min-height" OF YOUR PRIMARY "ul" TAG TO 484PX!
Linear and non-linear
If you want users to change between steps freely (without validations or the obligation to advance a step at a time), just remove .linear class from the primary ul:
<ul class="stepper">...</ul>
Form and inputs
If there is no "form" tag wrapping the ul, JS spawns it for the validate.js to work with the inputs (can be disabled). Since the primary funcion of stepper is to split some kind of form, for now, the only way to make a step required is to add "required" attribute to an input inside the .step-content container:
<input id="email" name="email" type="email" class="validate" required />
If the input is not valid, the icon will turn red until all required inputs become valid.
If you want to define your own attributes, just wrap the "ul" with a default "form", using any attributes you need:
<form action="youraction" method="yourmethod">
<ul class="stepper linear">...</ul>
</form>
If you want to submit your stepper, just create a submit button with "submit" type and no feedback or "next/previous-step" class and if there's a wrapping form && a validation function, it'll call it before the submit (just return false to prevent it):
<button class="waves-effect waves-dark btn" type="submit">SUBMIT</button>
Step labels
You can add you own step labels by adding a "data-step-label" to your "step-titles" tags. Just like that:
<div data-step-label="OMG, they're so small and cute!" class="step-title waves-effect">Step title</div>
API
Feedback function
There's a way to make the buttons run a function instead of proceeding, just add a data-feedback attribute with the function name to a ".next-step" classified button. Just like that:
<button class="waves-effect waves-dark btn next-step" data-feedback="checkEmailDB">CONTINUE</button>
<script>
function checkEmailDB(destroyFeedback, form, activeStepContent) {
// Do your stuff here
// Call destroyFeedback() function when you're done
// The true parameter will proceed to the next step besides destroying the preloader
destroyFeedback(true);
}
</script>
updateStepper method
If you want to the stepper to update the bindings (in case, for example, of AJAX loaded buttons), you can use updateStepper() method on the active instance.
instance.updateStepper();
resetStepper method
If you want to the stepper to it's original state (empty fields and options.firstActive), you can use resetStepper() method on the active instance. However, it can only be used on steppers wrapped in a form:
instance.resetStepper();
-
Step 1
-
Step 2
-
Step 3Finish!
Get Steps
You can get information about the steps by running:
var currentSteps = instace.getSteps()
And you'll get an object like this on var currentSteps:
{
steps: HTMLCollection, // The current steps in the DOM
active: {
step: HTMLElement, // The current active step in the DOM
index: number // The index of the active step
}
}
wrongStep method
If you want to show an error on the active step, just call this method. This is also the method called by the stepper when a validationFunction returns 'false':
instance.wrongStep();
The error will only be dismissed when there's some change in the inputs.
-
Step 1
-
Step 2
-
Step 3Finish!
Dynamically adding/removing steps
If you want to dinamically add and activate/remove steps, you can do this:
<script>
var elements;
// The element can be a string:
elements = '<div class="step">(...your step goes here...)</div>';
// An array of strings:
elements = ['<div class="step">(...your step goes here...)</div>', '<div class="step">(...your step goes here...)</div>'];
// An HTMLCollection:
elements = document.querySelectorAll('.steps-to-add');
// Or an HTMLElement:
elements = document.querySelector('.step-to-add');
// Then you just need to run
var addedSteps = instance.activateStep(elements, newStepsIndex);
// And if you want, you can remove them afterwards:
var removedSteps = instance.deactivateStep(addedSteps);
// Or add them again :P
var readdedSteps = instance.activateStep(removedSteps);
</script>
-
Step 1
-
Step 2
-
Step 3Finish!
Custom Events
There's currently 8 custom events in MStepper. All of them fires at the primary ul.stepper div:
- stepchange: fires everytime a step is opened and one is closed.
- stepopen: fires everytime a step is opened.
- stepclose: fires everytime a step is closed.
- nextstep: fires everytime the nextStep method is called.
- prevstep: fires everytime the prevStep method is called.
- steperror: fires everytime the wrongStep method is called.
- feedbacking: fires everytime the activateFeedback method is called.
- feedbackdestroyed: fires everytime the destroyFeedback method is called (and a feedback is actually destroyes).
Event Order
- Feedbacking
- Step Close
- Step Change
- Step Open
- Next / Previous Step
- Feedback Destroyed
Event Output
-
Step 1
-
Step 2
-
Step 3Finish!
Changelog
To get the change log, visit CHANGELOG.md page.
Ps: date format: d/m/y
Credits
Stepper is a plugin created by me, Igor Marcossi, inspired in MDL Stepper, a more powerful one that implements the same thing on Material Design Lite framework.
Donations
A penny for the poor dev
Just kidding, but the plugin surprisingly took me a bunch of time to make everything look pretty, so if I helped you, consider a donation. I'd be eternally grateful :)
What about a coffee?
I made even a cool donation button in a shape of a coffee cup, so why don't you buy me one? :D
Just click on the coffee cup below, c'mon, you can't resist!
Or you can send me some bitcoins :)
Just use this address: 1AE21GBjtQf5f7X3f1T2qdckgqcAhzxPdz