When you output data in Vue.js using the double curly bracket {{}}, it is interpreted as plain text.

For example, Let’s say we have a data property title that holds the title string along with some HTML tags in it.

<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <title>Vue.Js</title>
  </head>

  <body>
    <div id="app">
      <div>{{title}}</div>
    </div>
  </body>

  <script>
    const { createApp } = Vue;

    createApp({
      data() {
        return {
          title: "<h2> Getting started with Vue.js</h2>",
        };
      },
    }).mount("#app");
  </script>
</html>

Output:

v-html 1

In order for the data to be interpreted as raw HTML we make use of the directive v-html.

<!DOCTYPE html>
<html lang="en">
  <head>
    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <title>Vue.Js</title>
  </head>

  <body>
    <div id="app">
      <div v-html="title"></div>
    </div>
  </body>

  <script>
    const { createApp } = Vue;

    createApp({
      data() {
        return {
          title: "<h2> Getting started with Vue.js</h2>",
        };
      },
    }).mount("#app");
  </script>
</html>

Output:

v-html 2

In this case, we have specified the v-html tag to get the desired text interpolation.

<div v-html="title"></div>

Cross-site scripting (XSS)

It is important to note that using v-html can lead to a security vulnerability called Cross-site scripting (XSS). This allows hackers to inject client-side scripts easily. Hence, it is recommended to never use them on user-provided inputs.