Membuat Komponen Input Kustom dengan Dukungan v-model di Vue 3

Dalam pengembangan aplikasi menggunakan Vue 3, sering kali kita membutuhkan komponen input kustom yang dapat digunakan berulang kali di berbagai tempat. Salah satu fitur yang membuat Vue fleksibel adalah dukungan terhadap v-model
, yaitu mekanisme dua arah (two-way data binding) yang memudahkan sinkronisasi data antara komponen induk (parent) dan anak (child).
Namun, ketika membuat komponen sendiri, kita tidak bisa langsung menggunakan v-model
tanpa menambahkan logika tertentu. Artikel ini akan membahas secara detail cara membuat komponen input kustom di Vue 3 dengan dukungan penuh untuk v-model
, dilengkapi dengan beberapa contoh implementasi.
1. Memahami Cara Kerja v-model di Vue 3
Di Vue 2, v-model
biasanya bekerja dengan value
sebagai prop
dan input
sebagai event yang dipancarkan. Namun di Vue 3, v-model
telah disederhanakan dan lebih fleksibel:
v-model
akan secara default mengikat kemodelValue
(bukanvalue
lagi).- Setiap perubahan nilai harus dipancarkan (emit) menggunakan event
update:modelValue
.
Contoh singkat pada komponen bawaan:
<input v-model="username" />
Di balik layar, Vue akan melakukan binding seperti ini:
<input
:value="username"
@input="username = $event.target.value"
/>
2. Membuat Komponen Input Kustom Dasar
Mari kita buat komponen sederhana bernama CustomInput.vue
. Komponen ini akan menerima modelValue
sebagai prop, lalu memancarkan event update:modelValue
setiap kali pengguna mengetik sesuatu.
<template>
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
class="custom-input"
/>
</template>
<script setup>
defineProps({
modelValue: String
})
defineEmits(['update:modelValue'])
</script>
<style scoped>
.custom-input {
padding: 8px;
border: 1px solid #ccc;
border-radius: 6px;
}
</style>
Penggunaan di parent:
<template>
<CustomInput v-model="name" />
<p>Nama: {{ name }}</p>
</template>
<script setup>
import CustomInput from './CustomInput.vue'
import { ref } from 'vue'
const name = ref('')
</script>
Kini, setiap kali kita mengetik, nilai di parent (name
) akan otomatis berubah mengikuti input.
3. Menambahkan Props Tambahan
Komponen kustom tidak harus terbatas hanya menerima modelValue
. Misalnya, kita bisa menambahkan label, placeholder, atau bahkan tipe input (text
, password
, email
, dll.) agar lebih fleksibel.
<template>
<label>
{{ label }}
<input
:type="type"
:placeholder="placeholder"
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
class="custom-input"
/>
</label>
</template>
<script setup>
defineProps({
modelValue: String,
label: { type: String, default: '' },
placeholder: { type: String, default: '' },
type: { type: String, default: 'text' }
})
defineEmits(['update:modelValue'])
</script>
Penggunaan di parent:
<CustomInput
v-model="email"
label="Alamat Email"
placeholder="Masukkan email anda"
type="email"
/>
4. Mendukung Beberapa v-model (Multiple Binding)
Vue 3 mendukung lebih dari satu v-model
pada satu komponen. Ini berguna untuk kasus di mana kita ingin mengelola lebih dari satu nilai. Misalnya, membuat input password dengan toggle visibilitas.
<template>
<div>
<input
:type="visible ? 'text' : 'password'"
:value="password"
@input="$emit('update:password', $event.target.value)"
/>
<button type="button" @click="$emit('update:visible', !visible)">
{{ visible ? 'Sembunyikan' : 'Tampilkan' }}
</button>
</div>
</template>
<script setup>
defineProps({
password: String,
visible: Boolean
})
defineEmits(['update:password', 'update:visible'])
</script>
Penggunaan:
<PasswordInput v-model:password="userPassword" v-model:visible="isPasswordVisible" />
5. Validasi dan Pesan Error
Dalam banyak kasus, kita juga ingin agar input kustom mendukung validasi. Misalnya, kita dapat menampilkan pesan error jika input tidak sesuai aturan.
<template>
<div>
<label>
{{ label }}
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
:class="{ 'has-error': error }"
/>
</label>
<p v-if="error" class="error-text">{{ error }}</p>
</div>
</template>
<script setup>
defineProps({
modelValue: String,
label: String,
error: String
})
defineEmits(['update:modelValue'])
</script>
<style scoped>
.has-error {
border-color: red;
}
.error-text {
color: red;
font-size: 12px;
}
</style>
6. Menjadikan Komponen Lebih Reusable
Dengan menambahkan props, event, dan styling, kita bisa membuat komponen input kustom yang reusable untuk berbagai kebutuhan. Seiring pertumbuhan aplikasi, kita bahkan bisa membuat library komponen internal berisi berbagai input kustom, seperti:
- TextInput
- PasswordInput
- NumberInput dengan format angka
- DatePicker kustom
- Dropdown dengan v-model
Membuat komponen input kustom di Vue 3 dengan dukungan v-model
bukan hanya memudahkan pengelolaan data, tetapi juga membuat kode lebih rapi dan mudah digunakan kembali. Dengan memahami bahwa v-model
bekerja melalui modelValue
dan update:modelValue
, kita bisa mengembangkan berbagai variasi komponen input sesuai kebutuhan, baik sederhana maupun kompleks.
Mulailah dari komponen kecil seperti CustomInput
, lalu kembangkan menjadi library internal agar seluruh tim dapat menggunakannya dengan konsisten di seluruh aplikasi.