Reputation: 381
I'm trying to extract some repeated code into a Vue component. I want to be able to pass a list of CSS classes into the component using the class
HTML attribute, and merge those with a "default class" that is defined in the component. I want the public interface of this component to resemble a standard HTML element, but if I try to use "class" as a prop Vue throws an error about using a JS keyword. If I try to use $attrs, my default class gets wiped out.
Is it possible to merge HTML attributes with local component data, and use the result in my template? Below is what I would like to achieve:
<template>
<img src="imageUrl" class="classes"
</template>
export default {
computed: {
imageUrl() { return 'urlString' },
},
classes() { return `${this.$attrs.class} default-class` }
}
And I'd expect an implementer to be able to use my component like so:
<CustomImageComponent class="class-name another-class" />
Which I'd expect to render this:
<img src="urlString" class="class-name another-class default-class" />
Upvotes: 4
Views: 3480
Reputation: 35704
It already happens (automatically)
using <CustomImageComponent class="class-name another-class" />
will render<template><img src="imageUrl" class="my-default-class"/></template>
as <img src="imageUrl" class="my-default-class class-name another-class"/>
(in that order, with the in-template class first, and the passed classes after)
the issue is that if you have a nested DOM element that you want to apply it to, you cannot do that and you will have to use a prop
ie:
using <CustomImageComponent class="class-name another-class" />
will render<template><div><img src="imageUrl" class="my-default-class"/></div></template>
as <div class="class-name another-class"><img src="imageUrl" class="my-default-class"/></div>
and there's nothing you can do about that, other than use custom props.
Upvotes: 3
Reputation: 4845
A couple things you could do, both with this.$el.classList
.
On mounted:
mounted() {
this.$el.classList.add('default-class');
}
Computed property:
computed: {
classListWithDefault() {
return `${this.$el.classList.toString()} default-class`;
}
}
Upvotes: -1
Reputation: 1064
You just need to use v-bind:
or only colon(:)
before the attributes to pass data as a value and that's it, Vue automatically merge classes, see link below:
https://codesandbox.io/s/30oly1z326
Upvotes: 0