skip to content

In Vue 3, what does :style accept, and what does Vue do — and not do — when it applies a style object?

level: middleimportance: should knowfreq 44%

answer

  1. object, array of objects, or string
  2. camelCase or quoted kebab keys
  3. numbers get no unit
  4. prefixes tested at runtime

basics

~20 s

Vue's :style takes a CSS string, an object of properties, or an array of objects merged left to right. Vue adds vendor prefixes when needed and clears properties that disappear or become null, but it never appends units such as px to numbers.

solid answer

~40 s

`:style` maps to the element's `style` property. An **object** uses camelCase keys (`fontSize`) or quoted kebab-case keys (`'font-size'`); an **array** of objects is merged, later entries overriding earlier ones; a plain CSS string also works, and a static `style` attribute is merged with the binding. On each update Vue sets the properties that changed and **clears** any property whose value became `null`/`undefined` or that vanished from the object. It **auto-prefixes** a property the browser only supports with a vendor prefix, by testing at runtime, and an array value such as `display: ['-webkit-box', 'flex']` sets each in turn so the last supported one sticks. It supports CSS custom properties and `!important`. What it does not do: add units — `fontSize: 16` is not `16px`.

code

vue · 16 lines
vue
<script setup lang="ts">
import { ref } from 'vue'

const size = ref(18)
const highlighted = ref(false)
const base = { padding: '4px 8px', borderRadius: '0' }
</script>

<template>
  <span
    style="color: gray"
    :style="[base, { fontSize: size + 'px', outline: highlighted ? '2px solid' : null }]"
  >
    label
  </span>
</template>

go deeper

for a junior

Recall the object and array forms, camelCase keys, and that :style merges with a static style attribute.

for a middle

Explain how Vue diffs previous and next style objects, clears null or missing keys, and prefixes or tries multiple values.

for a senior

Avoid unitless-number bugs, prefer CSS custom properties for themeable values, and keep inline styles for truly dynamic values.

for a principal

Set the boundary between inline styles, CSS variables and class variants in the design system so theming stays in stylesheets.

## What :style accepts In Vue 3, `v-bind:style` (shorthand `:style`) corresponds to an element's `style` DOM property and accepts: - an **object** of CSS properties: `{ color: activeColor, fontSize: size + 'px' }`; - an **array** of such objects, merged into one: `[baseStyles, overridingStyles]`; - a **string** of CSS declarations: `:style="'font-size: 1em'"`. Keys may be **camelCase** (`fontSize`, recommended) or **kebab-case in quotes** (`'font-size'`). A static `style` attribute on the same element is merged with the binding — the guide's example renders `style="color: red; font-size: 1em;"` from `style="color: red"` plus `:style="'font-size: 1em'"`. ## What Vue does on each update When the bound value changes, Vue's style patcher compares the new object with the previous one: 1. For every property in the **previous** object that is missing or `null` in the new one, it clears that property. 2. For every property in the new object with a non-null value, it sets it. 3. A `null` or `undefined` value therefore **removes** the property — the idiomatic way to "turn a style off". Around that core it adds several conveniences: | Feature | Example | Behaviour | |---|---|---| | auto-prefixing | `{ userSelect: 'none' }` | if the browser only knows a prefixed name, Vue finds a supported `Webkit`/`Moz`/`ms` variant at runtime | | multiple values | `{ display: ['-webkit-box', 'flex'] }` | sets each value in turn; the browser keeps the last one it supports | | custom properties | `{ '--btn-accent': color }` | set with `setProperty`, usable from CSS as `var(--btn-accent)` | | `!important` | `{ color: 'red !important' }` | stripped from the value and passed as the priority | | development warning | `{ color: 'red;' }` | warns about an unexpected trailing semicolon | ## What Vue does not do - **No units.** `{ width: 120 }` assigns the number to `style.width`; the browser rejects a unitless length and the element keeps its previous width. Only properties that are genuinely unitless in CSS (`opacity`, `zIndex`, `lineHeight`, `flexGrow`) work with bare numbers. Write `width: size + 'px'` or `` `${size}px` ``. - **No validation.** An invalid value is silently ignored by the browser, not reported by Vue. - **No scoping.** Inline styles apply only to this element; scoped CSS and `v-bind()` inside `<style>` are separate features. ## The button again For a button whose accent colour comes from a prop, a CSS custom property keeps the stylesheet in charge and the binding tiny: ```vue <script setup lang="ts"> import { computed } from 'vue' const props = defineProps<{ accent?: string; width?: number }>() const style = computed(() => ({ '--btn-accent': props.accent ?? null, width: props.width != null ? `${props.width}px` : null, })) </script> <template> <button class="btn" :style="style"><slot /></button> </template> ``` When `accent` is not passed, the value is `null` and Vue leaves or removes the custom property, so the stylesheet default applies. ## Mistakes interviewers listen for - Passing a number for a length and expecting `px`. - Believing an array of style objects is applied as separate `style` attributes rather than merged. - Setting a property to `false` to hide it — `false` is not a CSS value, so the browser ignores the assignment and the old value stays; use `null`. - Adding prefixed and unprefixed keys by hand when Vue already picks the supported name.

  • In Vue 3, how do you remove a single inline style property through a :style object?
    Set its value to `null` or `undefined`, or drop the key from the object. On the next patch Vue clears every property that was present before and is now missing or null, leaving the rest of the inline style intact.
  • In Vue 3, what does :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }" render?
    Vue assigns each value in order, and the browser keeps the last one it accepts. In a current browser that is `display: flex`; an old browser that only knows a prefixed value keeps that one instead.

saying these in an interview costs you the question

  • Vue appends px to numeric values in :style objects.
  • :style keys must be kebab-case, exactly as in CSS files.
  • An array passed to :style applies only its last object.
  • Vue validates style values and warns about invalid CSS.
  • A :style binding replaces the static style attribute entirely.