This episode covers Vue's template language: interpolation and the v-bind, v-if, and v-for directives, event handling with v-on and its shorthands, conditional and list rendering, plus template refs and dynamic attributes for touching the DOM directly.

Every Vue application ultimately produces a view. And in Vue, views are written in templates — HTML syntax enriched with directives. Episode 4 is the episode where you really start to "see" the results of your work: rendering data to the screen, responding to clicks, displaying lists, and controlling what appears.
Templates are the everyday language of writing Vue UIs. Mastering them means you can build almost any interface: from product lists and forms to dynamic dashboards. We'll cover interpolation, the v-bind, v-if, v-for, and v-on directives, conditional and list rendering, and close with template refs and dynamic attributes.
The most basic way to render data is interpolation with {{ }}:
<script setup>
const nama = "Arman";
const hitung = 2 + 3;
</script>
<template>
<p>Halo, {{ nama }}</p>
<p>Total: {{ hitung }}</p>
</template>The expressions {{ nama }} and {{ hitung }} are evaluated as JavaScript. The page will display "Halo, Arman" and "Total: 5".
Mustache doesn't work inside HTML attributes. Use v-bind to connect attributes with expressions:
<script setup>
const imgUrl = "/images/logo.png";
const disabled = true;
</script>
<template>
<img v-bind:src="imgUrl" alt="Logo" />
<button :disabled="disabled">Simpan</button>
</template>v-bind:src and its shorthand :disabled make attribute values follow the state. In the code above, :disabled="disabled" binds the button's disabled attribute to the disabled variable.
Tip
v-bind can also bind many attributes at once from a single object using the v-bind="object" syntax. This is very useful for spreading props already collected into one variable.
v-on listens to DOM events and runs an expression or method:
<script setup>
import { ref } from "vue";
const jumlah = ref(0);
function tambah() {
jumlah.value = jumlah.value + 1;
}
</script>
<template>
<button v-on:click="tambah">Tambah</button>
<button @click="jumlah--">Kurang</button>
</template>@click is the shorthand for v-on:click. The expression jumlah-- runs directly, while tambah is a method. The event object can be accessed with the $event modifier.
Vue provides modifiers to handle event details:
<template>
<form @submit.prevent="kirim">
<input @keyup.enter="cari" />
<button @click.stop="klik">Hentikan</button>
</form>
</template>@submit.prevent calls preventDefault to stop the page from reloading, @keyup.enter only fires when the Enter key is pressed, and @click.stop stops the event from propagating to parent elements.
Two ways to control whether an element appears:
<script setup>
import { ref } from "vue";
const login = ref(false);
</script>
<template>
<p v-if="login">Selamat datang!</p>
<p v-else>Silakan login dulu.</p>
<p v-show="login">Ini tetap ada di DOM.</p>
</template>v-if removes and creates elements in the DOM; v-show only changes the CSS display. Use v-if for elements that rarely change and v-show for fast toggling that happens often.
Render a list with v-for using the item in list syntax:
<script setup>
const produk = [
{ id: 1, nama: "Keyboard", harga: 250000 },
{ id: 2, nama: "Mouse", harga: 150000 },
];
</script>
<template>
<ul>
<li v-for="item in produk" :key="item.id">
{{ item.nama }} - Rp{{ item.harga }}
</li>
</ul>
</template>v-for="item in produk" loops over each item, and :key="item.id" provides a unique identity — required so Vue can track list changes efficiently. Always use a stable key.
Sometimes you need to touch a DOM element directly, for example to focus it automatically. Use template refs:
<script setup>
import { ref, onMounted } from "vue";
const inputEl = ref(null);
onMounted(() => {
inputEl.value.focus();
});
</script>
<template>
<input ref="inputEl" placeholder="Ketik di sini" />
</template>The declaration ref="inputEl" links the element to a variable, and after onMounted the element is available at inputEl.value. Template refs are useful for integrating DOM libraries like charts or maps, which we'll put to use in episode 15.
Attributes collected in a single object can be spread with v-bind="attrs"; when the state changes, the attributes update automatically.
Episode 4 gave you the language for writing Vue UIs: interpolation with mustache, attribute binding with v-bind, events with v-on and modifiers, conditional rendering with v-if/v-show, list rendering with v-for, and direct DOM access through template refs.
Key takeaways:
{{ }} interpolation for text; v-bind for dynamic attributes.@click is the shorthand for v-on:click.v-if for conditions; v-else for its counterpart.v-for always comes with a stable :key.v-show is faster for frequent toggling.In the next episode 5, we'll go deeper into reactive state and the Composition API — ref and reactive in depth, computed and watchers, lifecycle hooks like onMounted and watchEffect, a comparison of the Composition API vs the Options API, and finally building custom composables for reusable logic.