Skip to content

Commit 7181909

Browse files
committed
forms
1 parent 3f0179e commit 7181909

File tree

1 file changed

+166
-89
lines changed

1 file changed

+166
-89
lines changed

src/guide/essentials/forms.md

Lines changed: 166 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
You can use the `v-model` directive to create two-way data bindings on form input, textarea, and select elements. It automatically picks the correct way to update the element based on the input type. Although a bit magical, `v-model` is essentially syntax sugar for updating data on user input events, plus special care for some edge cases.
66

77
::: tip Note
8-
`v-model` will ignore the initial `value`, `checked` or `selected` attributes found on any form elements. It will always treat the current active instance data as the source of truth. You should declare the initial value on the JavaScript side, inside the `data` option of your component.
8+
`v-model` will ignore the initial `value`, `checked` or `selected` attributes found on any form elements. It will always treat the current bound JavaScript state as the source of truth. You should declare the initial value on the JavaScript side, using <span class="options-api">the `data` option</span><span class="composition-api">reactivity APIs</span>.
99
:::
1010

1111
`v-model` internally uses different properties and emits different events for different input elements:
@@ -26,20 +26,37 @@ For languages that require an [IME](https://en.wikipedia.org/wiki/Input_method)
2626
<p>Message is: {{ message }}</p>
2727
```
2828

29-
<!-- <common-codepen-snippet title="Handling forms: basic v-model" slug="eYNPEqj" :preview="false" /> -->
29+
<div class="composition-api">
30+
31+
[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdCBzZXR1cD5cbmltcG9ydCB7IHJlZiB9IGZyb20gJ3Z1ZSdcblxuY29uc3QgbWVzc2FnZSA9IHJlZignJylcbjwvc2NyaXB0PlxuXG48dGVtcGxhdGU+XG5cdDxpbnB1dCB2LW1vZGVsPVwibWVzc2FnZVwiIHBsYWNlaG9sZGVyPVwiZWRpdCBtZVwiIC8+XG5cdDxwPk1lc3NhZ2UgaXM6IHt7IG1lc3NhZ2UgfX08L3A+XG48L3RlbXBsYXRlPiIsImltcG9ydC1tYXAuanNvbiI6IntcbiAgXCJpbXBvcnRzXCI6IHtcbiAgICBcInZ1ZVwiOiBcImh0dHBzOi8vc2ZjLnZ1ZWpzLm9yZy92dWUucnVudGltZS5lc20tYnJvd3Nlci5qc1wiXG4gIH1cbn0ifQ==)
32+
33+
</div>
34+
<div class="options-api">
35+
36+
[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdD5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgZGF0YSgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgbWVzc2FnZTogJydcbiAgICB9XG4gIH1cbn1cbjwvc2NyaXB0PlxuXG48dGVtcGxhdGU+XG5cdDxpbnB1dCB2LW1vZGVsPVwibWVzc2FnZVwiIHBsYWNlaG9sZGVyPVwiZWRpdCBtZVwiIC8+XG5cdDxwPk1lc3NhZ2UgaXM6IHt7IG1lc3NhZ2UgfX08L3A+XG48L3RlbXBsYXRlPiIsImltcG9ydC1tYXAuanNvbiI6IntcbiAgXCJpbXBvcnRzXCI6IHtcbiAgICBcInZ1ZVwiOiBcImh0dHBzOi8vc2ZjLnZ1ZWpzLm9yZy92dWUucnVudGltZS5lc20tYnJvd3Nlci5qc1wiXG4gIH1cbn0ifQ==)
37+
38+
</div>
3039

3140
### Multiline text
3241

3342
```vue-html
3443
<span>Multiline message is:</span>
3544
<p style="white-space: pre-line;">{{ message }}</p>
36-
<br />
3745
<textarea v-model="message" placeholder="add multiple lines"></textarea>
3846
```
3947

40-
<!-- <common-codepen-snippet title="Handling forms: textarea" slug="xxGyXaG" :preview="false" /> -->
48+
<div class="composition-api">
4149

42-
Interpolation on textareas won't work. Use `v-model` instead.
50+
[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdCBzZXR1cD5cbmltcG9ydCB7IHJlZiB9IGZyb20gJ3Z1ZSdcblxuY29uc3QgbWVzc2FnZSA9IHJlZignJylcbjwvc2NyaXB0PlxuXG48dGVtcGxhdGU+XG5cdDxzcGFuPk11bHRpbGluZSBtZXNzYWdlIGlzOjwvc3Bhbj5cblx0PHAgc3R5bGU9XCJ3aGl0ZS1zcGFjZTogcHJlLWxpbmU7XCI+e3sgbWVzc2FnZSB9fTwvcD5cblx0PHRleHRhcmVhIHYtbW9kZWw9XCJtZXNzYWdlXCIgcGxhY2Vob2xkZXI9XCJhZGQgbXVsdGlwbGUgbGluZXNcIj48L3RleHRhcmVhPlxuPC90ZW1wbGF0ZT4iLCJpbXBvcnQtbWFwLmpzb24iOiJ7XG4gIFwiaW1wb3J0c1wiOiB7XG4gICAgXCJ2dWVcIjogXCJodHRwczovL3NmYy52dWVqcy5vcmcvdnVlLnJ1bnRpbWUuZXNtLWJyb3dzZXIuanNcIlxuICB9XG59In0=)
51+
52+
</div>
53+
<div class="options-api">
54+
55+
[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdD5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgZGF0YSgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgbWVzc2FnZTogJydcbiAgICB9XG4gIH1cbn1cbjwvc2NyaXB0PlxuXG48dGVtcGxhdGU+XG5cdDxzcGFuPk11bHRpbGluZSBtZXNzYWdlIGlzOjwvc3Bhbj5cblx0PHAgc3R5bGU9XCJ3aGl0ZS1zcGFjZTogcHJlLWxpbmU7XCI+e3sgbWVzc2FnZSB9fTwvcD5cblx0PHRleHRhcmVhIHYtbW9kZWw9XCJtZXNzYWdlXCIgcGxhY2Vob2xkZXI9XCJhZGQgbXVsdGlwbGUgbGluZXNcIj48L3RleHRhcmVhPlxuPC90ZW1wbGF0ZT4iLCJpbXBvcnQtbWFwLmpzb24iOiJ7XG4gIFwiaW1wb3J0c1wiOiB7XG4gICAgXCJ2dWVcIjogXCJodHRwczovL3NmYy52dWVqcy5vcmcvdnVlLnJ1bnRpbWUuZXNtLWJyb3dzZXIuanNcIlxuICB9XG59In0=)
56+
57+
</div>
58+
59+
Note that interpolation inside `<textarea>` won't work. Use `v-model` instead.
4360

4461
```vue-html
4562
<!-- bad -->
@@ -58,88 +75,114 @@ Single checkbox, boolean value:
5875
<label for="checkbox">{{ checked }}</label>
5976
```
6077

61-
<!-- <common-codepen-snippet title="Handling forms: checkbox" slug="PoqyJVE" :preview="false" /> -->
78+
<div class="composition-api">
6279

63-
Multiple checkboxes, bound to the same array:
80+
[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdCBzZXR1cD5cbmltcG9ydCB7IHJlZiB9IGZyb20gJ3Z1ZSdcblxuY29uc3QgY2hlY2tlZCA9IHJlZih0cnVlKVxuPC9zY3JpcHQ+XG5cbjx0ZW1wbGF0ZT5cblx0PGlucHV0IHR5cGU9XCJjaGVja2JveFwiIGlkPVwiY2hlY2tib3hcIiB2LW1vZGVsPVwiY2hlY2tlZFwiIC8+XG5cdDxsYWJlbCBmb3I9XCJjaGVja2JveFwiPnt7IGNoZWNrZWQgfX08L2xhYmVsPlxuPC90ZW1wbGF0ZT4iLCJpbXBvcnQtbWFwLmpzb24iOiJ7XG4gIFwiaW1wb3J0c1wiOiB7XG4gICAgXCJ2dWVcIjogXCJodHRwczovL3NmYy52dWVqcy5vcmcvdnVlLnJ1bnRpbWUuZXNtLWJyb3dzZXIuanNcIlxuICB9XG59In0=)
6481

65-
```vue-html
66-
<div id="v-model-multiple-checkboxes">
67-
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames" />
68-
<label for="jack">Jack</label>
69-
<input type="checkbox" id="john" value="John" v-model="checkedNames" />
70-
<label for="john">John</label>
71-
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames" />
72-
<label for="mike">Mike</label>
73-
<br />
74-
<span>Checked names: {{ checkedNames }}</span>
7582
</div>
83+
<div class="options-api">
84+
85+
[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdD5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgZGF0YSgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgY2hlY2tlZDogdHJ1ZVxuICAgIH1cbiAgfVxufVxuPC9zY3JpcHQ+XG5cbjx0ZW1wbGF0ZT5cblx0PGlucHV0IHR5cGU9XCJjaGVja2JveFwiIGlkPVwiY2hlY2tib3hcIiB2LW1vZGVsPVwiY2hlY2tlZFwiIC8+XG5cdDxsYWJlbCBmb3I9XCJjaGVja2JveFwiPnt7IGNoZWNrZWQgfX08L2xhYmVsPlxuPC90ZW1wbGF0ZT4iLCJpbXBvcnQtbWFwLmpzb24iOiJ7XG4gIFwiaW1wb3J0c1wiOiB7XG4gICAgXCJ2dWVcIjogXCJodHRwczovL3NmYy52dWVqcy5vcmcvdnVlLnJ1bnRpbWUuZXNtLWJyb3dzZXIuanNcIlxuICB9XG59In0=)
86+
87+
</div>
88+
89+
We can also bind multiple checkboxes to the same array value:
90+
91+
<div class="composition-api">
92+
93+
```js
94+
const checkedNames = ref([])
7695
```
7796

97+
</div>
98+
<div class="options-api">
99+
78100
```js
79-
Vue.createApp({
101+
export default {
80102
data() {
81103
return {
82104
checkedNames: []
83105
}
84106
}
85-
}).mount('#v-model-multiple-checkboxes')
107+
}
108+
```
109+
110+
</div>
111+
112+
```vue-html
113+
<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
114+
<label for="jack">Jack</label>
115+
116+
<input type="checkbox" id="john" value="John" v-model="checkedNames">
117+
<label for="john">John</label>
118+
119+
<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
120+
<label for="mike">Mike</label>
121+
122+
<div>Checked names: {{ checkedNames }}</div>
86123
```
87124

88-
<!-- <common-codepen-snippet title="Handling forms: multiple checkboxes" slug="bGdmoyj" :preview="false" /> -->
125+
In this case, the `checkedNames` array will always contain the values from the currently checked boxes.
126+
127+
<div class="composition-api">
128+
129+
[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdCBzZXR1cD5cbmltcG9ydCB7IHJlZiB9IGZyb20gJ3Z1ZSdcblxuY29uc3QgY2hlY2tlZE5hbWVzID0gcmVmKFtdKVxuPC9zY3JpcHQ+XG5cbjx0ZW1wbGF0ZT5cbiAgPGlucHV0IHR5cGU9XCJjaGVja2JveFwiIGlkPVwiamFja1wiIHZhbHVlPVwiSmFja1wiIHYtbW9kZWw9XCJjaGVja2VkTmFtZXNcIiAvPlxuICA8bGFiZWwgZm9yPVwiamFja1wiPkphY2s8L2xhYmVsPlxuIFxuICA8aW5wdXQgdHlwZT1cImNoZWNrYm94XCIgaWQ9XCJqb2huXCIgdmFsdWU9XCJKb2huXCIgdi1tb2RlbD1cImNoZWNrZWROYW1lc1wiIC8+XG4gIDxsYWJlbCBmb3I9XCJqb2huXCI+Sm9objwvbGFiZWw+XG4gXG4gIDxpbnB1dCB0eXBlPVwiY2hlY2tib3hcIiBpZD1cIm1pa2VcIiB2YWx1ZT1cIk1pa2VcIiB2LW1vZGVsPVwiY2hlY2tlZE5hbWVzXCIgLz5cbiAgPGxhYmVsIGZvcj1cIm1pa2VcIj5NaWtlPC9sYWJlbD5cbiAgXG4gIDxkaXY+Q2hlY2tlZCBuYW1lczoge3sgY2hlY2tlZE5hbWVzIH19PC9kaXY+XG48L3RlbXBsYXRlPiIsImltcG9ydC1tYXAuanNvbiI6IntcbiAgXCJpbXBvcnRzXCI6IHtcbiAgICBcInZ1ZVwiOiBcImh0dHBzOi8vc2ZjLnZ1ZWpzLm9yZy92dWUucnVudGltZS5lc20tYnJvd3Nlci5qc1wiXG4gIH1cbn0ifQ==)
130+
131+
</div>
132+
<div class="options-api">
133+
134+
[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdD5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgZGF0YSgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgY2hlY2tlZE5hbWVzOiBbXVxuICAgIH1cbiAgfVxufVxuPC9zY3JpcHQ+XG5cbjx0ZW1wbGF0ZT5cbiAgPGlucHV0IHR5cGU9XCJjaGVja2JveFwiIGlkPVwiamFja1wiIHZhbHVlPVwiSmFja1wiIHYtbW9kZWw9XCJjaGVja2VkTmFtZXNcIiAvPlxuICA8bGFiZWwgZm9yPVwiamFja1wiPkphY2s8L2xhYmVsPlxuIFxuICA8aW5wdXQgdHlwZT1cImNoZWNrYm94XCIgaWQ9XCJqb2huXCIgdmFsdWU9XCJKb2huXCIgdi1tb2RlbD1cImNoZWNrZWROYW1lc1wiIC8+XG4gIDxsYWJlbCBmb3I9XCJqb2huXCI+Sm9objwvbGFiZWw+XG4gXG4gIDxpbnB1dCB0eXBlPVwiY2hlY2tib3hcIiBpZD1cIm1pa2VcIiB2YWx1ZT1cIk1pa2VcIiB2LW1vZGVsPVwiY2hlY2tlZE5hbWVzXCIgLz5cbiAgPGxhYmVsIGZvcj1cIm1pa2VcIj5NaWtlPC9sYWJlbD5cbiAgXG4gIDxkaXY+Q2hlY2tlZCBuYW1lczoge3sgY2hlY2tlZE5hbWVzIH19PC9kaXY+XG48L3RlbXBsYXRlPiIsImltcG9ydC1tYXAuanNvbiI6IntcbiAgXCJpbXBvcnRzXCI6IHtcbiAgICBcInZ1ZVwiOiBcImh0dHBzOi8vc2ZjLnZ1ZWpzLm9yZy92dWUucnVudGltZS5lc20tYnJvd3Nlci5qc1wiXG4gIH1cbn0ifQ==)
135+
136+
</div>
89137

90138
### Radio
91139

92140
```vue-html
93-
<div id="v-model-radiobutton">
94-
<input type="radio" id="one" value="One" v-model="picked" />
95-
<label for="one">One</label>
96-
<br />
97-
<input type="radio" id="two" value="Two" v-model="picked" />
98-
<label for="two">Two</label>
99-
<br />
100-
<span>Picked: {{ picked }}</span>
101-
</div>
102-
```
141+
<input type="radio" id="one" value="One" v-model="picked" />
142+
<label for="one">One</label>
103143
104-
```js
105-
Vue.createApp({
106-
data() {
107-
return {
108-
picked: ''
109-
}
110-
}
111-
}).mount('#v-model-radiobutton')
144+
<input type="radio" id="two" value="Two" v-model="picked" />
145+
<label for="two">Two</label>
146+
147+
<div>Picked: {{ picked }}</div>
112148
```
113149

114-
<!-- <common-codepen-snippet title="Handling forms: radiobutton" slug="MWwPEMM" :preview="false" /> -->
150+
<div class="composition-api">
151+
152+
[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdCBzZXR1cD5cbmltcG9ydCB7IHJlZiB9IGZyb20gJ3Z1ZSdcblxuY29uc3QgcGlja2VkID0gcmVmKCdPbmUnKVxuPC9zY3JpcHQ+XG5cbjx0ZW1wbGF0ZT5cblx0PGlucHV0IHR5cGU9XCJyYWRpb1wiIGlkPVwib25lXCIgdmFsdWU9XCJPbmVcIiB2LW1vZGVsPVwicGlja2VkXCIgLz5cblx0PGxhYmVsIGZvcj1cIm9uZVwiPk9uZTwvbGFiZWw+XG5cblx0PGlucHV0IHR5cGU9XCJyYWRpb1wiIGlkPVwidHdvXCIgdmFsdWU9XCJUd29cIiB2LW1vZGVsPVwicGlja2VkXCIgLz5cblx0PGxhYmVsIGZvcj1cInR3b1wiPlR3bzwvbGFiZWw+XG5cblx0PGRpdj5QaWNrZWQ6IHt7IHBpY2tlZCB9fTwvZGl2PlxuPC90ZW1wbGF0ZT4iLCJpbXBvcnQtbWFwLmpzb24iOiJ7XG4gIFwiaW1wb3J0c1wiOiB7XG4gICAgXCJ2dWVcIjogXCJodHRwczovL3NmYy52dWVqcy5vcmcvdnVlLnJ1bnRpbWUuZXNtLWJyb3dzZXIuanNcIlxuICB9XG59In0=)
153+
154+
</div>
155+
<div class="options-api">
156+
157+
[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdD5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgZGF0YSgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgcGlja2VkOiAnT25lJ1xuICAgIH1cbiAgfVxufVxuPC9zY3JpcHQ+XG5cbjx0ZW1wbGF0ZT5cblx0PGlucHV0IHR5cGU9XCJyYWRpb1wiIGlkPVwib25lXCIgdmFsdWU9XCJPbmVcIiB2LW1vZGVsPVwicGlja2VkXCIgLz5cblx0PGxhYmVsIGZvcj1cIm9uZVwiPk9uZTwvbGFiZWw+XG5cblx0PGlucHV0IHR5cGU9XCJyYWRpb1wiIGlkPVwidHdvXCIgdmFsdWU9XCJUd29cIiB2LW1vZGVsPVwicGlja2VkXCIgLz5cblx0PGxhYmVsIGZvcj1cInR3b1wiPlR3bzwvbGFiZWw+XG5cblx0PGRpdj5QaWNrZWQ6IHt7IHBpY2tlZCB9fTwvZGl2PlxuPC90ZW1wbGF0ZT4iLCJpbXBvcnQtbWFwLmpzb24iOiJ7XG4gIFwiaW1wb3J0c1wiOiB7XG4gICAgXCJ2dWVcIjogXCJodHRwczovL3NmYy52dWVqcy5vcmcvdnVlLnJ1bnRpbWUuZXNtLWJyb3dzZXIuanNcIlxuICB9XG59In0=)
158+
159+
</div>
115160

116161
### Select
117162

118163
Single select:
119164

120165
```vue-html
121-
<div id="v-model-select" class="demo">
122-
<select v-model="selected">
123-
<option disabled value="">Please select one</option>
124-
<option>A</option>
125-
<option>B</option>
126-
<option>C</option>
127-
</select>
128-
<span>Selected: {{ selected }}</span>
129-
</div>
130-
```
166+
<select v-model="selected">
167+
<option disabled value="">Please select one</option>
168+
<option>A</option>
169+
<option>B</option>
170+
<option>C</option>
171+
</select>
131172
132-
```js
133-
Vue.createApp({
134-
data() {
135-
return {
136-
selected: ''
137-
}
138-
}
139-
}).mount('#v-model-select')
173+
<div>Selected: {{ selected }}</div>
140174
```
141175

142-
<!-- <common-codepen-snippet title="Handling forms: select" slug="KKpGydL" :preview="false" /> -->
176+
<div class="composition-api">
177+
178+
[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdCBzZXR1cD5cbmltcG9ydCB7IHJlZiB9IGZyb20gJ3Z1ZSdcblxuY29uc3Qgc2VsZWN0ZWQgPSByZWYoJycpXG48L3NjcmlwdD5cblxuPHRlbXBsYXRlPlxuICA8c2VsZWN0IHYtbW9kZWw9XCJzZWxlY3RlZFwiPlxuICAgIDxvcHRpb24gZGlzYWJsZWQgdmFsdWU9XCJcIj5QbGVhc2Ugc2VsZWN0IG9uZTwvb3B0aW9uPlxuICAgIDxvcHRpb24+QTwvb3B0aW9uPlxuICAgIDxvcHRpb24+Qjwvb3B0aW9uPlxuICAgIDxvcHRpb24+Qzwvb3B0aW9uPlxuICA8L3NlbGVjdD5cbiAgPHNwYW4+IFNlbGVjdGVkOiB7eyBzZWxlY3RlZCB9fTwvc3Bhbj5cbjwvdGVtcGxhdGU+IiwiaW1wb3J0LW1hcC5qc29uIjoie1xuICBcImltcG9ydHNcIjoge1xuICAgIFwidnVlXCI6IFwiaHR0cHM6Ly9zZmMudnVlanMub3JnL3Z1ZS5ydW50aW1lLmVzbS1icm93c2VyLmpzXCJcbiAgfVxufSJ9)
179+
180+
</div>
181+
<div class="options-api">
182+
183+
[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdD5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgZGF0YSgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgc2VsZWN0ZWQ6ICcnXG4gICAgfVxuICB9XG59XG48L3NjcmlwdD5cblxuPHRlbXBsYXRlPlxuICA8c2VsZWN0IHYtbW9kZWw9XCJzZWxlY3RlZFwiPlxuICAgIDxvcHRpb24gZGlzYWJsZWQgdmFsdWU9XCJcIj5QbGVhc2Ugc2VsZWN0IG9uZTwvb3B0aW9uPlxuICAgIDxvcHRpb24+QTwvb3B0aW9uPlxuICAgIDxvcHRpb24+Qjwvb3B0aW9uPlxuICAgIDxvcHRpb24+Qzwvb3B0aW9uPlxuICA8L3NlbGVjdD5cbiAgPHNwYW4+IFNlbGVjdGVkOiB7eyBzZWxlY3RlZCB9fTwvc3Bhbj5cbjwvdGVtcGxhdGU+IiwiaW1wb3J0LW1hcC5qc29uIjoie1xuICBcImltcG9ydHNcIjoge1xuICAgIFwidnVlXCI6IFwiaHR0cHM6Ly9zZmMudnVlanMub3JnL3Z1ZS5ydW50aW1lLmVzbS1icm93c2VyLmpzXCJcbiAgfVxufSJ9)
184+
185+
</div>
143186

144187
:::tip Note
145188
If the initial value of your `v-model` expression does not match any of the options, the `<select>` element will render in an "unselected" state. On iOS this will cause the user not being able to select the first item because iOS does not fire a change event in this case. It is therefore recommended to provide a disabled option with an empty value, as demonstrated in the example above.
@@ -153,27 +196,39 @@ Multiple select (bound to array):
153196
<option>B</option>
154197
<option>C</option>
155198
</select>
156-
<br />
157-
<span>Selected: {{ selected }}</span>
199+
200+
<div>Selected: {{ selected }}</div>
158201
```
159202

160-
<!-- <common-codepen-snippet title="Handling forms: select bound to array" slug="gOpBXPz" tab="result" :preview="false" /> -->
203+
<div class="composition-api">
161204

162-
Dynamic options rendered with `v-for`:
205+
[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdCBzZXR1cD5cbmltcG9ydCB7IHJlZiB9IGZyb20gJ3Z1ZSdcblxuY29uc3Qgc2VsZWN0ZWQgPSByZWYoW10pXG48L3NjcmlwdD5cblxuPHRlbXBsYXRlPlxuICA8c2VsZWN0IHYtbW9kZWw9XCJzZWxlY3RlZFwiIG11bHRpcGxlPlxuICAgIDxvcHRpb24+QTwvb3B0aW9uPlxuICAgIDxvcHRpb24+Qjwvb3B0aW9uPlxuICAgIDxvcHRpb24+Qzwvb3B0aW9uPlxuICA8L3NlbGVjdD5cblxuICA8ZGl2PlNlbGVjdGVkOiB7eyBzZWxlY3RlZCB9fTwvZGl2PlxuPC90ZW1wbGF0ZT4iLCJpbXBvcnQtbWFwLmpzb24iOiJ7XG4gIFwiaW1wb3J0c1wiOiB7XG4gICAgXCJ2dWVcIjogXCJodHRwczovL3NmYy52dWVqcy5vcmcvdnVlLnJ1bnRpbWUuZXNtLWJyb3dzZXIuanNcIlxuICB9XG59In0=)
163206

164-
```vue-html
165-
<div id="v-model-select-dynamic" class="demo">
166-
<select v-model="selected">
167-
<option v-for="option in options" :value="option.value">
168-
{{ option.text }}
169-
</option>
170-
</select>
171-
<span>Selected: {{ selected }}</span>
172207
</div>
208+
<div class="options-api">
209+
210+
[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdD5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgZGF0YSgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgc2VsZWN0ZWQ6IFtdXG4gICAgfVxuICB9XG59XG48L3NjcmlwdD5cblxuPHRlbXBsYXRlPlxuICA8c2VsZWN0IHYtbW9kZWw9XCJzZWxlY3RlZFwiIG11bHRpcGxlPlxuICAgIDxvcHRpb24+QTwvb3B0aW9uPlxuICAgIDxvcHRpb24+Qjwvb3B0aW9uPlxuICAgIDxvcHRpb24+Qzwvb3B0aW9uPlxuICA8L3NlbGVjdD5cblxuICA8ZGl2PlNlbGVjdGVkOiB7eyBzZWxlY3RlZCB9fTwvZGl2PlxuPC90ZW1wbGF0ZT4iLCJpbXBvcnQtbWFwLmpzb24iOiJ7XG4gIFwiaW1wb3J0c1wiOiB7XG4gICAgXCJ2dWVcIjogXCJodHRwczovL3NmYy52dWVqcy5vcmcvdnVlLnJ1bnRpbWUuZXNtLWJyb3dzZXIuanNcIlxuICB9XG59In0=)
211+
212+
</div>
213+
214+
Dynamic options rendered with `v-for`:
215+
216+
<div class="composition-api">
217+
218+
```js
219+
const selected = ref('A')
220+
221+
const options = ref([
222+
{ text: 'One', value: 'A' },
223+
{ text: 'Two', value: 'B' },
224+
{ text: 'Three', value: 'C' }
225+
])
173226
```
227+
</div>
228+
<div class="options-api">
174229

175230
```js
176-
Vue.createApp({
231+
export default {
177232
data() {
178233
return {
179234
selected: 'A',
@@ -184,10 +239,30 @@ Vue.createApp({
184239
]
185240
}
186241
}
187-
}).mount('#v-model-select-dynamic')
242+
}
188243
```
244+
</div>
189245

190-
<!-- <common-codepen-snippet title="Handling forms: select with dynamic options" slug="abORVZm" :preview="false" /> -->
246+
```vue-html
247+
<select v-model="selected">
248+
<option v-for="option in options" :value="option.value">
249+
{{ option.text }}
250+
</option>
251+
</select>
252+
253+
<div>Selected: {{ selected }}</div>
254+
```
255+
256+
<div class="composition-api">
257+
258+
[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdCBzZXR1cD5cbmltcG9ydCB7IHJlZiB9IGZyb20gJ3Z1ZSdcblxuY29uc3Qgc2VsZWN0ZWQgPSByZWYoJ0EnKVxuXG5jb25zdCBvcHRpb25zID0gcmVmKFtcbiAgeyB0ZXh0OiAnT25lJywgdmFsdWU6ICdBJyB9LFxuICB7IHRleHQ6ICdUd28nLCB2YWx1ZTogJ0InIH0sXG4gIHsgdGV4dDogJ1RocmVlJywgdmFsdWU6ICdDJyB9XG5dKVxuPC9zY3JpcHQ+XG5cbjx0ZW1wbGF0ZT5cbiAgPHNlbGVjdCB2LW1vZGVsPVwic2VsZWN0ZWRcIj5cbiAgICA8b3B0aW9uIHYtZm9yPVwib3B0aW9uIGluIG9wdGlvbnNcIiA6dmFsdWU9XCJvcHRpb24udmFsdWVcIj5cbiAgICAgIHt7IG9wdGlvbi50ZXh0IH19XG4gICAgPC9vcHRpb24+XG4gIDwvc2VsZWN0PlxuXG5cdDxkaXY+U2VsZWN0ZWQ6IHt7IHNlbGVjdGVkIH19PC9kaXY+XG48L3RlbXBsYXRlPiIsImltcG9ydC1tYXAuanNvbiI6IntcbiAgXCJpbXBvcnRzXCI6IHtcbiAgICBcInZ1ZVwiOiBcImh0dHBzOi8vc2ZjLnZ1ZWpzLm9yZy92dWUucnVudGltZS5lc20tYnJvd3Nlci5qc1wiXG4gIH1cbn0ifQ==)
259+
260+
</div>
261+
<div class="options-api">
262+
263+
[Try it in the Playground](https://sfc.vuejs.org/#eyJBcHAudnVlIjoiPHNjcmlwdD5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgZGF0YSgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgc2VsZWN0ZWQ6ICdBJyxcbiAgICAgIG9wdGlvbnM6IFtcbiAgICAgICAgeyB0ZXh0OiAnT25lJywgdmFsdWU6ICdBJyB9LFxuICAgICAgICB7IHRleHQ6ICdUd28nLCB2YWx1ZTogJ0InIH0sXG4gICAgICAgIHsgdGV4dDogJ1RocmVlJywgdmFsdWU6ICdDJyB9XG4gICAgICBdXG4gICAgfVxuICB9XG59XG48L3NjcmlwdD5cblxuPHRlbXBsYXRlPlxuICA8c2VsZWN0IHYtbW9kZWw9XCJzZWxlY3RlZFwiPlxuICAgIDxvcHRpb24gdi1mb3I9XCJvcHRpb24gaW4gb3B0aW9uc1wiIDp2YWx1ZT1cIm9wdGlvbi52YWx1ZVwiPlxuICAgICAge3sgb3B0aW9uLnRleHQgfX1cbiAgICA8L29wdGlvbj5cbiAgPC9zZWxlY3Q+XG5cblx0PGRpdj5TZWxlY3RlZDoge3sgc2VsZWN0ZWQgfX08L2Rpdj5cbjwvdGVtcGxhdGU+IiwiaW1wb3J0LW1hcC5qc29uIjoie1xuICBcImltcG9ydHNcIjoge1xuICAgIFwidnVlXCI6IFwiaHR0cHM6Ly9zZmMudnVlanMub3JnL3Z1ZS5ydW50aW1lLmVzbS1icm93c2VyLmpzXCJcbiAgfVxufSJ9)
264+
265+
</div>
191266

192267
## Value Bindings
193268

@@ -211,14 +286,22 @@ But sometimes we may want to bind the value to a dynamic property on the current
211286
### Checkbox
212287

213288
```vue-html
214-
<input type="checkbox" v-model="toggle" true-value="yes" false-value="no" />
289+
<input
290+
type="checkbox"
291+
v-model="toggle"
292+
true-value="yes"
293+
false-value="no" />
215294
```
216295

217-
```js
218-
// when checked:
219-
vm.toggle === 'yes'
220-
// when unchecked:
221-
vm.toggle === 'no'
296+
`true-value` and `false-value` are Vue-specific attributes that only works with `v-model`. Here the `toggle` property's value will be set to `'yes'` when the box is checked, and set to `'no'` when unchecked. You can also bind them to dynamic values using `v-bind`:
297+
298+
299+
```vue-html
300+
<input
301+
type="checkbox"
302+
v-model="toggle"
303+
:true-value="dynamicTrueValue"
304+
:false-value="dynamicFalseValue" />
222305
```
223306

224307
:::tip Tip
@@ -228,13 +311,11 @@ The `true-value` and `false-value` attributes don't affect the input's `value` a
228311
### Radio
229312

230313
```vue-html
231-
<input type="radio" v-model="pick" v-bind:value="a" />
314+
<input type="radio" v-model="pick" :value="first" />
315+
<input type="radio" v-model="pick" :value="second" />
232316
```
233317

234-
```js
235-
// when checked:
236-
vm.pick === vm.a
237-
```
318+
`pick` will be set to the value of `first` when the first radio input is checked, and set to the value of `second` when the second one is checked.
238319

239320
### Select Options
240321

@@ -245,11 +326,7 @@ vm.pick === vm.a
245326
</select>
246327
```
247328

248-
```js
249-
// when selected:
250-
typeof vm.selected // => 'object'
251-
vm.selected.number // => 123
252-
```
329+
`v-model` supports value bindings of non-string values as well! In the above example, when the option is selected, `selected` will be set to the object literal value of `{ number: 123 }`.
253330

254331
## Modifiers
255332

0 commit comments

Comments
 (0)