vuetify
vuetify copied to clipboard
[Feature Request] Add a slot to be able to change the icon template in v-stepper-step
Problem to solve
This would allow for more costumization of the stepper icon, currently the icon can only be passed as editableIcon, errorIcon, completedIcon
This would allow to change the logic of the displayed icons and to give more flexibility for their display (For example to add an image, or to change the default number or text to an icon, and to change the size and color of the stepper icon)
Related #3963
Proposed solution
To add a scoped slot named "icon" that will pass the props of the parent (hasError, completed, editable, isActive, isInactive and the icons props) so that we can declare our components like so
<v-stepper-step>
<template #icon="step">
<v-icon v-if="step.isActive">ActiveIcon</v-icon>
<v-icon v-else-if="step.editable">{{step.editableIcon}}</v-icon>
//Etc ...
</template>
Step Label
</v-stepper-step>
I also was looking to change the icons to Font Awesome icons in the steppers, and it just won't work âšī¸ Maybe there's some way to "hack" it?
There is a way to hack it but it's really really bad and I don't recommend it
You can use the :step property to change the default text and it accepts html so you can enter something like
<i class="fa fa-smt" >
inside, the problem you'll find is it's also the identifier of the step so you can't have the same twice and you also can't use components
@jaminroe https://vuetifyjs.com/en/framework/icons#install-font-awesome-5-icons
v-stepper-step
also has complete-icon
, edit-icon
, and error-icon
props.
@KaelWD @johnleider Any news?
It should be as simple as doing this
genStepContent () {
//Simply return the content of the "icon" slot if it's defined with the entire VStepperStep node passed as a prop
if (typeof this.$scopedSlots.icon === 'function') {
return this.$scopedSlots.icon(this);
}
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
},
Seems this was forgotten but is in good demand, so a little bump
This would be really nice, also the ability to change the color of the individual steps because there isn't a horizontal timeline, and the stepper would work perfectly as a horizontal timeline if it was a bit more customizable.
Checking on this... need it :)
In dire need of this too
Same here!
A workaround for this is putting the icon unicode value in the :before of the step. This becomes a hassle if you have a lot of steps though.
@Tofandel how used this solution ? i try add like you but not working đ¤đ¤
- VStepperStep
genStepContent () {
if (typeof this.$scopedSlots.icon === 'function') {
return this.$scopedSlots.icon(this);
}
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
},
- My code
<v-stepper-step
:color="steps > 1 ? 'success' : 'primary'"
:complete="steps > 1"
step="1"
>
<template #icon="step">
<v-icon v-if="step.isActive">headset</v-icon>
<v-icon>headset</v-icon>
</template>
<span
class="headline"
:class="steps > 1 ? 'success--text' : 'primary--text'"
>Call Center</span
>
</v-stepper-step>
@ibraahim6 This is not a solution, only a proposal to be added to vuetify, you'd need to modify the vuetify source and recompile it as a local dependency of your project for it to work (which is quite a pain if you use vuetify-loader), my code is also possibly not up to date anymore
@ibraahim6 @Tofandel I think the cleanest solution right now is to extend
the VStepperStep
with custom code:
VeStepperStep (Vuetify Extended Stepper Step):
import { VStepperStep } from 'vuetify/lib/components/VStepper'
export default {
// eslint-disable-next-line
name: 've-stepper-step',
extends: VStepperStep,
methods: {
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 if (this.$attrs.icon) {
// this "else if" branch is added,
// so the step can display custom
// Vuetify icons
children.push(this.genIcon(this.$attrs.icon))
} else {
children.push(String(this.step))
}
return children
},
},
}
To make it work smoothly with the stepper, the VStepper
should also be extended:
import { VStepper } from 'vuetify/lib'
export default {
// eslint-disable-next-line
name: 've-stepper',
extends: VStepper,
methods: {
register(item) {
if (
item.$options.name === 've-stepper-step' ||
item.$options.name === 'v-stepper-step'
) {
this.steps.push(item)
} else if (item.$options.name === 'v-stepper-content') {
item.isVertical = this.vertical
this.content.push(item)
}
},
unregister(item) {
if (
item.$options.name === 've-stepper-step' ||
item.$options.name === 'v-stepper-step'
) {
this.steps = this.steps.filter(i => i !== item)
} else if (item.$options.name === 'v-stepper-content') {
item.isVertical = this.vertical
this.content = this.content.filter(i => i !== item)
}
},
},
}
This way, when you include & use ve-stepper
you can add steps of ve-stepper-step
that accept an icon
prop - everything else stays the same as it is with the original VStepper
& VStepperStep
.
Working piece: @codesandbox
https://user-images.githubusercontent.com/5388876/121066542-4df2a180-c7ca-11eb-9f4d-47c006788caa.mov
@gegeke If you name it v-stepper-step
instead of ve-stepper-step
you don't need to extend the stepper as well, vue allows for components to have the same name
@gegeke If you name it
v-stepper-step
instead ofve-stepper-step
you don't need to extend the stepper as well, vue allows for components to have the same name
@Tofandel thanks for the comment - I agree, fewer changes are needed that way, less to maintain.
But to me, it's a cleaner solution if names are changed - easier to keep track of modifications & I like to use the project-naming convention if there is one for components (be they written or just customized).
bump
Am I not seeing something.. or?
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
},
Now just take a look at getIcon
genIcon (icon: string) {
return this.$createElement(VIcon, icon)
},
Ok, let's take a look at VIcon.ts getIcon function
getIcon (): VuetifyIcon {
let iconName = ''
if (this.$slots.default) iconName = this.$slots.default[0].text!.trim()
return remapInternalIcon(this, iconName)
},
Inside remapInternalIcon there is a lines
// Look for overrides
if (iconName.startsWith('$')) {
// Get the target icon name
const iconPath = `$vuetify.icons.values.${iconName.split('$').pop()!.split('.').pop()}`
// Now look up icon indirection name,
// e.g. '$vuetify.icons.values.cancel'
const override = getObjectValueByPath(vm, iconPath, iconName)
if (typeof override === 'string') iconName = override
else return override
}
Take a look at const iconPath..
So theoretically it could be possible to add custom item and used it?
Vuetify configuration
icons: {
iconFont: 'mdi',
values: {
myCustomIcon: 'example'
}
},
Looks like vuetify adds that custom icon
<v-stepper-step
complete-icon="$myCustomIcon"
edit-icon="$myCustomIcon"
editable
step="1"
>
But still this is not working :/