Reputation: 1353
I'm new to vue.js. Here is my problem:
In a *.vue file like this:
<template>
<div id="a">
</div>
</template>
<script>
export default {
name: 'SquareButton',
props: ['color']
}
</script>
<style scoped>
#a {
background-color: ?
}
<style>
How can I use the props color
in background-color:
(where is a ?
now).
Thanks.
Upvotes: 134
Views: 130372
Reputation: 719
I know we're talking vue 2 here, but in case anyone from vue 3 lands in this question (like I did), vue 3 introduced a much cleaner way to do this:
<template>
<div id="a">
</div>
</template>
<script>
export default {
name: 'SquareButton',
props: ['color']
}
</script>
<style scoped>
#a {
background-color: v-bind(color);
}
<style>
What Vue actually does behind the scenes is the same "introducing css variables through component's style process", but it sure looks much better on the eyes now.
Documentation source: https://vuejs.org/api/sfc-css-features.html#v-bind-in-css
Upvotes: 57
Reputation: 35380
As a note for myself and future readers, if you're using Vue 3's Composition API with <script setup lang="ts">
, the following syntax works correctly:
In the script
section, define your prop(s):
const props = defineProps<{
myprop: string;
}>()
In the styles
section:
.some-class {
background-image: v-bind('props.myprop');
}
Note that the prop name is enclosed in quotes.
Upvotes: 2
Reputation: 77
A simple component to add css styles in Vue 2, using <style> tag
<template>
<span class="embed-style" style="display: none" v-html="cssText"></span>
</template>
<script>
export default {
name: 'EmbedStyle',
props: {
rules: {
type: Array,
default() {
return []
}
}
},
computed: {
cssText() {
let txt = ' ';
this.rules.forEach(rule => {
txt += `${rule.selector} { `;
for (const prop in rule.props) {
txt += `${this.fromCamelCase(prop)}: ${rule.props[prop]}; `;
}
txt += ' } ';
})
return `<style>${txt}</style>`;
}
},
methods: {
fromCamelCase(str) {
let newStr = '';
for (let l = 0; l < str.length; l++) {
if (/[A-Z]/.test(str.charAt(l))) {
const lower = str.charAt(l).toLowerCase();
newStr += `-${lower}`;
} else {
newStr += str.charAt(l);
}
}
return newStr;
}
}
}
</script>
Then we use this way:
<template>
<embed-style :rules="[cssRules]" />
...
computed: {
cssRules() {
return {
selector: '.toaster .toast',
props: {
animationDuration: `${this.duration}ms !important`,
transitionDuration: `${this.duration}ms !important`
}
}
}
}
Upvotes: 0
Reputation: 1572
You could utilise the CSS var(--foo-bar)
function. It is also useful if you are trying to pass an asset that has its own dynamic path, like Shopify does.
This method also works for styling the :before
and :after
elements as they refer back to the style applied on the owner element.
Using the original post example for passing a colour:
<template>
<div
id="a"
:style="{ '--colour': color }">
</div>
</template>
<script>
export default {
name: 'SquareButton',
props: ['color']
}
</script>
<style scoped>
#a {
background-color: var(--colour);
}
</style>
Using the original post example for passing an URL:
<template>
<div
id="a"
:style="{ '--image-url': 'url(' + image + ')' }">
</div>
</template>
<script>
export default {
name: 'SquareButton',
props: ['image']
}
</script>
<style scoped>
#a {
background-url: var(--image-url);
}
</style>
Upvotes: 5
Reputation: 5508
Vue 3 added new way of binding styles, so now you can easily bind your props to css properties.
Read source: https://learnvue.co/2021/05/how-to-use-vue-css-variables-reactive-styles-rfc/
<template>
<div>
<div class="text">hello</div>
</div>
</template>
<script>
export default {
data() {
return {
color: 'red',
}
}
}
</script>
<style>
.text {
color: v-bind(color);
}
</style>
Upvotes: 10
Reputation: 570
As we are in 2020 now, I suggest using this trick with a css function called var
<template>
<div id="a" :style="cssVars"></div>
</template>
<script>
export default {
props: ['color'],
computed: {
cssVars () {
return{
/* variables you want to pass to css */
'--color': this.color,
}
}
}
<script>
<style scoped>
#a{
background-color: var(--color);
}
</style>
This method is very useful because it allows you to update the passed values through css later on (for example when you apply hover event).
Upvotes: 47
Reputation: 1371
You actually can!
You should define the CSS variables in a Computed Property, then call the computed property as a style attribute to the element that will require the CSS variable, and finally you may use the variable within the tags at the bottom of your document.
new Vue({
el: '#app',
data: function() {
return {
baseFontSize: 1,
bgHoverColor: "#00cc00",
hoverContent: "Hovering!"
}
},
computed: {
cssProps() {
return {
'--hover-font-size': (this.baseFontSize * 2) + "em",
'--bg-hover-color': this.bgHoverColor,
'--hover-content': JSON.stringify(this.hoverContent)
}
}
}
})
div {
margin: 1em;
}
div.test:hover {
background-color: var(--bg-hover-color);
font-size: var(--hover-font-size);
}
div.test:hover::after {
margin-left: 1em;
content: var(--hover-content);
}
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<div id="app" :style="cssProps">
<div>Hover text: <input type="text" v-model="hoverContent"></div>
<div>Hover color: <input type="color" v-model="bgHoverColor"></div>
<div class="test">Hover over me</div>
</div>
Or have a look here: https://codepen.io/richardtallent/pen/yvpERW/
And here: https://github.com/vuejs/vue/issues/7346
Upvotes: 131
Reputation: 2452
Why not just use :style
prop in this way:
<template>
<div :style="{ backgroundColor: color }">
</template>
<script>
export default {
props: {
color: {
type: String,
default: ''
}
}
}
</script>
Make sure you define css properties in camelCase style.
Upvotes: 24
Reputation: 3921
If you need css that can't be applied by a style attribute like pseudo classes or media queries, what I do is the following:
Create a globally available style component when initializing Vue (you need it as otherwise you run into linting issues). It creates a style tag that simply renders the content in the slot:
I would only use this if you really need both dynamic values in your css and css features that can't be applied to a style attribute.
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
Vue.config.productionTip = false
Vue.component('v-style', {
render: function(createElement) {
return createElement('style', this.$slots.default)
}
})
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
Then use it at the top of your template like this and you get the full JavaScript scope of your component and the full css syntax combined:
<template>
<v-style>
@media screen and (max-width: 820px) {
.gwi-text-media-{{ this.id }} {
background-image: url({{ mobileThumb }});
}
}
</v-style>
</template>
It seems a bit hacky to me, but it does it's job and I would rather go like this in some cases than having to add additional JS for mouse-over or resize events that have a big potential to slow down your application performance.
Upvotes: 17
Reputation: 1998
You don't. You use a computed property and there you use the prop to return the style of the div, like this:
<template>
<div id="a" :style="style" @mouseover="mouseOver()">
</div>
</template>
<script>
export default {
name: 'SquareButton',
props: ['color'],
computed: {
style () {
return 'background-color: ' + this.hovering ? this.color: 'red';
}
},
data () {
return {
hovering: false
}
},
methods: {
mouseOver () {
this.hovering = !this.hovering
}
}
}
</script>
<style scoped>
<style>
Upvotes: 86