|
| 1 | +# Class and Style Bindings |
| 2 | + |
| 3 | +A common need for data binding is manipulating an element's class list and its inline styles. Since they are both attributes, we can use `v-bind` to handle them: we only need to calculate a final string with our expressions. However, meddling with string concatenation is annoying and error-prone. For this reason, Vue provides special enhancements when `v-bind` is used with `class` and `style`. In addition to strings, the expressions can also evaluate to objects or arrays. |
| 4 | + |
| 5 | +## Binding HTML Classes |
| 6 | + |
| 7 | +[Watch a free video lesson on Vue School](https://vueschool.io/lessons/vuejs-dynamic-classes?friend=vuejs) |
| 8 | + |
| 9 | +### Object Syntax |
| 10 | + |
| 11 | +We can pass an object to `v-bind:class` to dynamically toggle classes: |
| 12 | + |
| 13 | +```html |
| 14 | +<div v-bind:class="{ active: isActive }"></div> |
| 15 | +``` |
| 16 | + |
| 17 | +The above syntax means the presence of the `active` class will be determined by the [truthiness](https://developer.mozilla.org/en-US/docs/Glossary/Truthy) of the data property `isActive`. |
| 18 | + |
| 19 | +You can have multiple classes toggled by having more fields in the object. In addition, the `v-bind:class` directive can also co-exist with the plain `class` attribute. So given the following template: |
| 20 | + |
| 21 | +```html |
| 22 | +<div |
| 23 | + class="static" |
| 24 | + v-bind:class="{ active: isActive, 'text-danger': hasError }" |
| 25 | +></div> |
| 26 | +``` |
| 27 | + |
| 28 | +And the following data: |
| 29 | + |
| 30 | +```js |
| 31 | +data: { |
| 32 | + isActive: true, |
| 33 | + hasError: false |
| 34 | +} |
| 35 | +``` |
| 36 | + |
| 37 | +It will render: |
| 38 | + |
| 39 | +```html |
| 40 | +<div class="static active"></div> |
| 41 | +``` |
| 42 | + |
| 43 | +When `isActive` or `hasError` changes, the class list will be updated accordingly. For example, if `hasError` becomes `true`, the class list will become `"static active text-danger"`. |
| 44 | + |
| 45 | +The bound object doesn't have to be inline: |
| 46 | + |
| 47 | +```html |
| 48 | +<div v-bind:class="classObject"></div> |
| 49 | +``` |
| 50 | + |
| 51 | +```js |
| 52 | +data: { |
| 53 | + classObject: { |
| 54 | + active: true, |
| 55 | + 'text-danger': false |
| 56 | + } |
| 57 | +} |
| 58 | +``` |
| 59 | + |
| 60 | +This will render the same result. We can also bind to a [computed property](computed.md) that returns an object. This is a common and powerful pattern: |
| 61 | + |
| 62 | +```html |
| 63 | +<div v-bind:class="classObject"></div> |
| 64 | +``` |
| 65 | + |
| 66 | +```js |
| 67 | +data: { |
| 68 | + isActive: true, |
| 69 | + error: null |
| 70 | +}, |
| 71 | +computed: { |
| 72 | + classObject() { |
| 73 | + return { |
| 74 | + active: this.isActive && !this.error, |
| 75 | + 'text-danger': this.error && this.error.type === 'fatal' |
| 76 | + } |
| 77 | + } |
| 78 | +} |
| 79 | +``` |
| 80 | + |
| 81 | +### Array Syntax |
| 82 | + |
| 83 | +We can pass an array to `v-bind:class` to apply a list of classes: |
| 84 | + |
| 85 | +```html |
| 86 | +<div v-bind:class="[activeClass, errorClass]"></div> |
| 87 | +``` |
| 88 | + |
| 89 | +```js |
| 90 | +data: { |
| 91 | + activeClass: 'active', |
| 92 | + errorClass: 'text-danger' |
| 93 | +} |
| 94 | +``` |
| 95 | + |
| 96 | +Which will render: |
| 97 | + |
| 98 | +```html |
| 99 | +<div class="active text-danger"></div> |
| 100 | +``` |
| 101 | + |
| 102 | +If you would like to also toggle a class in the list conditionally, you can do it with a ternary expression: |
| 103 | + |
| 104 | +```html |
| 105 | +<div v-bind:class="[isActive ? activeClass : '', errorClass]"></div> |
| 106 | +``` |
| 107 | + |
| 108 | +This will always apply `errorClass`, but will only apply `activeClass` when `isActive` is truthy. |
| 109 | + |
| 110 | +However, this can be a bit verbose if you have multiple conditional classes. That's why it's also possible to use the object syntax inside array syntax: |
| 111 | + |
| 112 | +```html |
| 113 | +<div v-bind:class="[{ active: isActive }, errorClass]"></div> |
| 114 | +``` |
| 115 | + |
| 116 | +### With Components |
| 117 | + |
| 118 | +> This section assumes knowledge of [Vue Components](TODO:components.html). Feel free to skip it and come back later. |
| 119 | +
|
| 120 | +When you use the `class` attribute on a custom component, those classes will be added to the component's root element. Existing classes on this element will not be overwritten. |
| 121 | + |
| 122 | +For example, if you declare this component: |
| 123 | + |
| 124 | +```js |
| 125 | +const MyComponent = { |
| 126 | + template: '<p class="foo bar">Hi!</p>' |
| 127 | +} |
| 128 | +``` |
| 129 | + |
| 130 | +Then add some classes when using it: |
| 131 | + |
| 132 | +```html |
| 133 | +<div id="app"> |
| 134 | + <my-component class="baz boo"></my-component> |
| 135 | +</div> |
| 136 | +``` |
| 137 | + |
| 138 | +```js |
| 139 | +Vue.createApp().mount( |
| 140 | + { |
| 141 | + components: { |
| 142 | + 'my-component': MyComponent |
| 143 | + } |
| 144 | + }, |
| 145 | + '#app' |
| 146 | +) |
| 147 | +``` |
| 148 | + |
| 149 | +The rendered HTML will be: |
| 150 | + |
| 151 | +```html |
| 152 | +<p class="foo bar baz boo">Hi</p> |
| 153 | +``` |
| 154 | + |
| 155 | +> TODO: needs a check after https://github.com/vuejs/rfcs/blob/attr-fallthrough/active-rfcs/0000-attr-fallthrough.md is merged |
| 156 | +
|
| 157 | +The same is true for class bindings: |
| 158 | + |
| 159 | +```html |
| 160 | +<my-component v-bind:class="{ active: isActive }"></my-component> |
| 161 | +``` |
| 162 | + |
| 163 | +When `isActive` is truthy, the rendered HTML will be: |
| 164 | + |
| 165 | +```html |
| 166 | +<p class="foo bar active">Hi</p> |
| 167 | +``` |
| 168 | + |
| 169 | +## Binding Inline Styles |
| 170 | + |
| 171 | +### Object Syntax |
| 172 | + |
| 173 | +The object syntax for `v-bind:style` is pretty straightforward - it looks almost like CSS, except it's a JavaScript object. You can use either camelCase or kebab-case (use quotes with kebab-case) for the CSS property names: |
| 174 | + |
| 175 | +```html |
| 176 | +<div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div> |
| 177 | +``` |
| 178 | + |
| 179 | +```js |
| 180 | +data: { |
| 181 | + activeColor: 'red', |
| 182 | + fontSize: 30 |
| 183 | +} |
| 184 | +``` |
| 185 | + |
| 186 | +It is often a good idea to bind to a style object directly so that the template is cleaner: |
| 187 | + |
| 188 | +```html |
| 189 | +<div v-bind:style="styleObject"></div> |
| 190 | +``` |
| 191 | + |
| 192 | +```js |
| 193 | +data: { |
| 194 | + styleObject: { |
| 195 | + color: 'red', |
| 196 | + fontSize: '13px' |
| 197 | + } |
| 198 | +} |
| 199 | +``` |
| 200 | + |
| 201 | +Again, the object syntax is often used in conjunction with computed properties that return objects. |
| 202 | + |
| 203 | +### Array Syntax |
| 204 | + |
| 205 | +The array syntax for `v-bind:style` allows you to apply multiple style objects to the same element: |
| 206 | + |
| 207 | +```html |
| 208 | +<div v-bind:style="[baseStyles, overridingStyles]"></div> |
| 209 | +``` |
| 210 | + |
| 211 | +### Auto-prefixing |
| 212 | + |
| 213 | +When you use a CSS property that requires [vendor prefixes](https://developer.mozilla.org/en-US/docs/Glossary/Vendor_Prefix) in `v-bind:style`, for example `transform`, Vue will automatically detect and add appropriate prefixes to the applied styles. |
| 214 | + |
| 215 | +### Multiple Values |
| 216 | + |
| 217 | +You can provide an array of multiple (prefixed) values to a style property, for example: |
| 218 | + |
| 219 | +```html |
| 220 | +<div v-bind:style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div> |
| 221 | +``` |
| 222 | + |
| 223 | +This will only render the last value in the array which the browser supports. In this example, it will render `display: flex` for browsers that support the unprefixed version of flexbox. |
0 commit comments