4

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" />
2
  • 1
    I'm not sure if I understand the question 100%, but it looks to me like you're looking for class="my-static-class" :class="my-passed-classes". which combines static and variables in class name Commented Dec 13, 2018 at 17:21
  • That's what I'm after, but I want to use HTML attributes rather than a custom prop. Commented Dec 13, 2018 at 17:26

3 Answers 3

3

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.

Sign up to request clarification or add additional context in comments.

1 Comment

No idea why this wasn't working for me... I must've had a syntax error or something, but tried again and it worked. Thanks!
0

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

Comments

-1

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`;
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.