Input Bindings

When using form inputs we usually need two-way binding. In order to achieve this we can use the :value attribute with the @input event.

<input 
  :value="text" 
  @input="event => text = event.target.value"
>

This can be verbose. Another way of having the same behavior is using the v-model directive.

<!-- For input text we only use v-model -->
<p>Message is: {{ message }}</p>
<input v-model="message" />

<!-- Fot textarea we use it similar to input text, and not like text interpolation -->
<span>Multiline message is:</span>
<p style="white-space: pre-line;">{{ message }}</p>
<textarea v-model="message"></textarea>

For checkboxes, when used for a single checkbox without the value attribute, the state can take a boolean value (true | false). We can use the true-value and false-value attributes to assign the values that the state can take. These can be fixed values, or dynamic values.

For multiple related checkboxes, we assign the same model, having every element a different value for value attribute. In this case, the state instead of holding true-false values, store a list of values as an array, according to the checkboxes values.

const checked = ref(false)
const checkedNames = reactive([])

const trueValue = ref('good')
const falseValue = ref('bad')
<!-- On single checkbox the state can take boolean values: true or false -->
<input type="checkbox" id="checkbox" v-model="checked" />
<label>{{ checked }}</label>

<!-- Fixed values for true and false -->
<input
  type="checkbox"
  v-model="toggle"
  true-value="yes"
  false-value="no" 
/>

<!-- Dynamic values for true and false -->
<input
  type="checkbox"
  v-model="toggle"
  :true-value="trueValue"
  :false-value="falseValue" 
/>

<div>Checked names: {{ checkedNames }}</div>
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames" /><label>Jack</label>
<input type="checkbox" id="john" value="John" v-model="checkedNames" /><label>John</label>
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames" /><label>Mike</label>

Radio inputs work similar to checkboxes, but the only difference is that the model can take one and just one value from all related radio inputs. The values can be fixed or dynamic.

<!-- Checkbox takes only one fixed value from all radios -->
<div>Picked: {{ picked }}</div>
<input type="radio" id="one" value="One" v-model="picked" /><label>One</label>
<input type="radio" id="two" value="Two" v-model="picked" /><label>Two</label>

<!-- It can take also a dyanmic value -->
<input type="radio" v-model="pick" :value="first" />
<input type="radio" v-model="pick" :value="second" />

For dropdowns, the model is set to the <select> tag, which can take the value from any selected option. This value can be not only a fixed value, but also a dynamic one, and it can hold complex values like objects.

<div>Selected: {{ selected }}</div>
<select v-model="selected">
  <option disabled value="">Please select one</option>
  <option value="A">A</option>
  <option value="B">B</option>
  <option value="C">C</option>
</select>

<select v-model="selected">
  <!-- inline object literal -->
  <option :value="{ number: 123 }">123</option>
</select>

Modifiers

There are three modifiers that can change the behavior or apply an action over the model value. .lazy updates the value after the change event instead the input event. .number casts automatically the value. And .trim removes spaces before and after the value.

<!-- Synced after "change" instead of "input" -->
<input v-model.lazy="msg" />

<!-- Cast the value to number -->
<input v-model.number="age" />

<!-- Trim empty characters before and after the value -->
<input v-model.trim="msg" />

References