Icons in Vuetify VStepper? There’s a way
Working with Vue 2 & Vuetify is a pure joy: thoroughly thought-out & well-working components, customizable theme (in the scope of Material Design); it definitely enables you to quickly go forward with your project.
But there are cases when you need something that’s not in the library, the pre-built components just can’t do that: it’s not a big thing, so creating a Material Themed component would be way too much of a hassle, but still, this little piece of UX/UI not done right would throw the UI far off from how it was intended to be.
One such case: a stepper that should show custom icons instead of numbers or strings.
In Vuetify, the stepper component is VStepper, and no, it’s unfortunately not able to display custom icons (VIcons). There’s a feature request for that in the Vuetify Github issues, but I think it’s not going to be delivered as the issue has been there for over 2 years and the next version, Vuetify 3 is already in its alpha, so presumably, the earlier releases won’t get new features.
So, to give a solution, I’d like to show you a way how you can overcome this limitation — with a non-invasive, “npm install proof” way, just by using the already available tools in Vue 2 & Vuetify 2.
Adding a custom VIcon to Vuetify VStepper
1. Extending the VStepperStep component
In Vue, you can extend a component (Vue docs here). This is one of the methods to re-use code: this implements a merge strategy that we need in this case — to overwrite existing options.
Looking through the VStepperStep component, you can see that the option we need to overwrite is the method genStepContent (Github link to code). This method is responsible for deciding what to display in the step:
// code clipped from Vuetify VStepperStep.ts:genStepContent () {
const children = []
if (this.hasError) {
children.push(this.genIcon(this.errorIcon))
} else if (this.complete) {
if (this.editable) {
children.push(this.genIcon(this.editIcon))
} else {
children.push(this.genIcon(this.completeIcon))
}
} else {
children.push(String(this.step))
}
return children
}
I’d like to modify this function:
- if the icon attribute is present on the component & if the icon attribute is not falsy, then it should have a custom behavior
- if the icon attribute has a truthy value, then we should try to “pass it” to a VIcon (so Vuetify does what it’s supposed to do)
It’s easier done than said, as the VStepperStep is already prepared to handle icons (e.g. for error state):
- Create the VStepperStepIcon.vue file in the components folder
- There should be only a <script> tag in this new .vue file (it doesn’t have its own template)
- Import the component you want to extend
- Add the default export: an object with name, extends & methods keys
- The name should be kebab cased (e.g. v-stepper-step-icon)
- The extends option should be the imported component (VStepperStep)
- In the methods you should add one function: genStepContent() {}
So, your VStepperStepIcon.vue should look like this:
2. Modifying the VStepper, so it displays the new component
Even if the VStepperStepIcon component works, the default VStepper just won’t display it: VStepper only handles VStepperStep & VStepperContent components (register & unregister methods), nothing else. We need to add our new component to the list of handled components by extending the VStepper.
The methods of extension is the same as it was with VStepperStepIcon, but I also put some smaller utility functions there (not required for the solution, just this felt the correct way to go; additions are functions outside of the default export):
3. Adding new components to Vuetify
You can manually add components to Vuetify — so, we can use our new VStepperIcon and VStepperStepIcon in our project easily:
4. And now: use it
<template>
<v-stepper-icon>
<v-stepper-step-icon
icon="mdi-account-outline"
>
Name of step
</v-stepper-step-icon>
</v-stepper-icon>
</template>
5. Just look at this beauty :)
Conclusion
If you need to put an icon in Vuetify VStepperStep, then you can easily do it by extending VStepperStep and the VStepper components: by using the extends option and overwriting the default functions you can customize the default behavior of a Vue component.
Written with ❤️ & the intention to help.