Template Option Example

In Vue's Options API, the template option serves as a declarative way to define a component's markup structure. Vue takes this string template, compiles it into a render function, and subsequently generates the actual DOM based on the component's reactive state. This approach shines in environments without a build step, for quick prototyping, or during teaching demonstrations. However, when working with Single File Components (SFCs), the <template> block is processed during the build phase, making it the recommended best practice for production environments.

The template option typically works in harmony with other foundational component options like data, props, computed, and methods. Within these templates, developers can leverage standard interpolation {{ }} alongside directives such as v-if, v-for, v-bind, and v-on.
The following example demonstrates how to globally register a component and utilize a string-based template:

<div id="app"></div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script>
  const { createApp } = Vue;

  const HelloBox = {
    template: `
      <div class="hello-box">
        <h3>{{ title }}</h3>
        <p>{{ message }}</p>
      </div>
    `,
    data() {
      return {
        title: 'Template Option Example',
        message: 'This is a string-based template.'
      };
    }
  };

  createApp({
    components: { HelloBox },
    template: `<HelloBox />`
  }).mount('#app');
</script>

In this setup, both the root and child components leverage the template option. Note that if you are using the runtime-only build of Vue, string templates cannot be compiled on the fly and will require either render functions or pre-compiled templates.

Integrating Component Options in Templates

The template property has direct access to data properties and methods defined on the component instance. Consider this counter component:

const Counter = {
  template: `
    <div>
      <p>Current Count: {{ count }}</p>
      <button @click="increment">Increment</button>
      <button @click="reset">Reset</button>
    </div>
  `,
  data() {
    return { count: 0 };
  },
  methods: {
    increment() {
      this.count++;
    },
    reset() {
      this.count = 0;
    }
  }
};

Computed properties can also be seamlessly integrated into templates:

const UserCard = {
  props: ['name', 'age'],
  template: `
    <div>
      <p>Name: {{ name }}</p>
      <p>Age: {{ age }}</p>
      <p>Is Adult: {{ isAdult }}</p>
    </div>
  `,
  computed: {
    isAdult() {
      return this.age >= 18 ? 'Yes' : 'No';
    }
  }
};

Differences from Single File Components

  • Compilation Timing: The template option is usually compiled at runtime, whereas SFC <template> blocks are compiled at build time.
  • Performance: Pre-compiled templates deliver superior runtime performance, while runtime compilation introduces additional bundle weight and execution overhead.
  • Developer Experience: Single File Components support advanced features like syntax highlighting, scoped styling, and Hot Module Replacement (HMR).
  • Use Cases: The template option is ideal for lightweight demos, quick pages, or build-free setups, while production-grade applications strongly favor SFCs.

Essential Best Practices and Caveats

  • Vue 3 supports multiple root nodes per template, but certain structural directives or attribute inheritance scenarios still require careful markup design.
  • When writing in-DOM templates, sticking to kebab-case for component tags (e.g., <hello-box>) is strongly recommended.
  • When utilizing JavaScript template literals (backticks), be mindful of potential syntax conflicts with ${} interpolation expressions.
  • Avoid heavy reliance on runtime compilation for production systems; prioritize pre-compiled assets.
  • Keep templates clean by moving complex expressions into computed properties or methods.
  • If the console warns that a component provided a template option but runtime compilation is not supported, it indicates that your current Vue build lacks the template compiler.

Complete Example: Todo Application

const TodoItem = {
  props: ['todo'],
  template: `
    <li>
      <input type="checkbox" :checked="todo.done" @change="$emit('toggle', todo.id)">
      <span :style="{ textDecoration: todo.done ? 'line-through' : 'none' }">
        {{ todo.text }}
      </span>
    </li>
  `
};

const TodoApp = {
  components: { TodoItem },
  template: `
    <div>
      <h3>Todo List</h3>
      <input v-model="newText" @keyup.enter="addTodo" placeholder="Add a new task">
      <button @click="addTodo">Add</button>
      <ul>
        <TodoItem
          v-for="todo in todos"
          :key="todo.id"
          :todo="todo"
          @toggle="toggleTodo"
        />
      </ul>
    </div>
  `,
  data() {
    return {
      newText: '',
      todos: [
        { id: 1, text: 'Learn template option', done: false },
        { id: 2, text: 'Write sample code', done: true }
      ]
    };
  },
  methods: {
    addTodo() {
      const text = this.newText.trim();
      if (!text) return;
      this.todos.push({ id: Date.now(), text, done: false });
      this.newText = '';
    },
    toggleTodo(id) {
      const todo = this.todos.find(item => item.id === id);
      if (todo) todo.done = !todo.done;
    }
  }
};

This comprehensive example illustrates how the template option coordinates smoothly with props, custom events, v-model, v-for, and methods. Decomposing templates into modular child components keeps the application architecture clean and maintainable.

Conclusion

The template option remains an intuitive mechanism for rendering views within Vue's Options API. It excels in rapid prototyping and lightweight applications. Understanding its underlying compilation mechanics, data binding strategies, and distinctions from Single File Components empowers developers to make informed architectural decisions across different project scales. For robust enterprise applications, adopting Single File Components is always the preferred route for maximizing performance and maintainability.