Skip to main content
Vue uses an HTML-based template syntax that allows you to declaratively bind the rendered DOM to the underlying component instance’s data.

Text Interpolation

The most basic form of data binding is text interpolation using the “Mustache” syntax (double curly braces):
<template>
  <span>Message: {{ msg }}</span>
</template>

<script setup>
import { ref } from 'vue'

const msg = ref('Hello Vue!')
</script>
The mustache tag will be replaced with the value of the msg property from the component instance. It will also be updated whenever the msg property changes.

Raw HTML

The double mustaches interpret data as plain text, not HTML. To output real HTML, use the v-html directive:
<template>
  <p>Using text interpolation: {{ rawHtml }}</p>
  <p>Using v-html directive: <span v-html="rawHtml"></span></p>
</template>

<script setup>
import { ref } from 'vue'

const rawHtml = ref('<span style="color: red">This is red</span>')
</script>
Dynamically rendering arbitrary HTML can be dangerous as it can lead to XSS vulnerabilities. Only use v-html on trusted content and never on user-provided content.

Attribute Bindings

Mustaches cannot be used inside HTML attributes. Instead, use a v-bind directive:
<template>
  <div v-bind:id="dynamicId"></div>
  <!-- Shorthand -->
  <div :id="dynamicId"></div>
</template>

<script setup>
import { ref } from 'vue'

const dynamicId = ref('my-id')
</script>

Boolean Attributes

Boolean attributes are attributes that indicate true/false values by their presence:
<template>
  <button :disabled="isButtonDisabled">Click me</button>
</template>

<script setup>
import { ref } from 'vue'

const isButtonDisabled = ref(true)
</script>

Dynamically Binding Multiple Attributes

You can bind an object of attributes to an element:
<template>
  <div v-bind="objectOfAttrs"></div>
</template>

<script setup>
import { reactive } from 'vue'

const objectOfAttrs = reactive({
  id: 'container',
  class: 'wrapper',
  style: 'color: red'
})
</script>

Using JavaScript Expressions

Vue supports the full power of JavaScript expressions inside data bindings:
<template>
  <div>{{ number + 1 }}</div>
  <div>{{ ok ? 'YES' : 'NO' }}</div>
  <div>{{ message.split('').reverse().join('') }}</div>
  <div :id="`list-${id}`"></div>
</template>
Each binding can only contain one single expression. An expression is a piece of code that can be evaluated to a value.

Expressions Not Supported

The following will NOT work:
<template>
  <!-- This is a statement, not an expression -->
  <div>{{ var a = 1 }}</div>

  <!-- Flow control won't work, use ternary expressions -->
  <div>{{ if (ok) { return message } }}</div>
</template>

Calling Functions

You can call component methods inside binding expressions:
<template>
  <time :title="toTitleDate(date)" :datetime="date">
    {{ formatDate(date) }}
  </time>
</template>

<script setup>
import { ref } from 'vue'

const date = ref(new Date())

function formatDate(date) {
  return date.toLocaleDateString()
}

function toTitleDate(date) {
  return date.toISOString()
}
</script>
Functions called inside binding expressions will be called every time the component updates, so they should not have side effects or be computationally expensive. For expensive operations, use computed properties instead.

Directives

Directives are special attributes with the v- prefix. Vue provides several built-in directives:
  • v-if - Conditional rendering
  • v-for - List rendering
  • v-on - Event handling
  • v-bind - Attribute binding
  • v-model - Two-way binding
  • v-show - Toggle display
  • v-html - Raw HTML
  • v-text - Text content
  • v-once - One-time rendering
  • v-memo - Memoize subtree

Directive Syntax

A directive’s full syntax looks like this:
v-directive:argument.modifier="value"
1

Directive name

The directive name (e.g., if, for, bind)
2

Argument (optional)

Follows the colon (e.g., :href in v-bind:href)
3

Modifiers (optional)

Denoted by a dot (e.g., .prevent in v-on:submit.prevent)
4

Value

The JavaScript expression to bind

Dynamic Arguments

You can use a JavaScript expression in a directive argument by wrapping it with square brackets:
<template>
  <a v-bind:[attributeName]="url">Link</a>
  <!-- Shorthand -->
  <a :[attributeName]="url">Link</a>
  
  <button v-on:[eventName]="handler">Click</button>
  <!-- Shorthand -->
  <button @[eventName]="handler">Click</button>
</template>

<script setup>
import { ref } from 'vue'

const attributeName = ref('href')
const eventName = ref('click')
const url = ref('https://vuejs.org')

function handler() {
  console.log('Clicked!')
}
</script>
Dynamic argument expressions have some syntax constraints. Spaces and quotes are invalid inside HTML attribute names. Avoid uppercase keys as browsers coerce attribute names to lowercase.

Modifiers

Modifiers are special postfixes denoted by a dot, indicating that a directive should be bound in some special way.

Event Modifiers

From packages/runtime-dom/src/directives/vOn.ts:34-47, Vue provides event modifiers like:
<template>
  <!-- Stop propagation -->
  <button @click.stop="doThis">Click</button>
  
  <!-- Prevent default -->
  <form @submit.prevent="onSubmit">Submit</form>
  
  <!-- Chain modifiers -->
  <button @click.stop.prevent="doThat">Click</button>
  
  <!-- Just the modifier -->
  <form @submit.prevent></form>
</template>
Available modifiers: .stop, .prevent, .self, .capture, .once, .passive

Key Modifiers

When listening for keyboard events:
<template>
  <!-- Only call handler when key is Enter -->
  <input @keyup.enter="submit" />
  
  <!-- Multiple keys -->
  <input @keyup.enter.space="handler" />
</template>

System Modifier Keys

From packages/runtime-dom/src/directives/vOn.ts:11, system modifiers are:
<template>
  <!-- Ctrl + Click -->
  <div @click.ctrl="handler">Ctrl+Click</div>
  
  <!-- Alt + Enter -->
  <input @keyup.alt.enter="clear" />
  
  <!-- Exact modifier -->
  <button @click.ctrl.exact="onCtrlClick">Ctrl only</button>
</template>
System modifiers: .ctrl, .alt, .shift, .meta

Render Functions

For advanced use cases, Vue also provides the h() function from packages/runtime-core/src/h.ts for programmatically creating VNodes:
import { h } from 'vue'

const vnode = h(
  'div', // type
  { id: 'foo', class: 'bar' }, // props
  [
    h('span', 'Hello'),
    h('span', 'World')
  ] // children
)
This is useful when templates are too constraining or when building higher-order components.

Reactivity Fundamentals

Learn about reactive state

Conditional Rendering

Control element rendering with v-if and v-show

List Rendering

Render lists with v-for

Event Handling

Handle user events

Build docs developers (and LLMs) love