VueJS - Binding
Vue 3 - Attribute, Class, Style, and Form Bindings
Section titled “Vue 3 - Attribute, Class, Style, and Form Bindings”Vue’s data binding system allows you to declaratively connect your application’s data to the DOM. This chapter covers how to bind HTML attributes, classes, inline styles, and form inputs using directives like v-bind and v-model in Vue 3.
Binding HTML Attributes (v-bind or :)
Section titled “Binding HTML Attributes (v-bind or :)”You cannot use standard mustache syntax ({{ }}) inside HTML attributes. Instead, use the v-bind directive or its shorthand : to bind an attribute to a JavaScript expression or data property.
Example
Section titled “Example”<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Vue 3 Attribute Binding</title> <script src="https://unpkg.com/vue@3"></script></head><body> <div id="app-attr"> <!-- Incorrect: Will render href="{{ googleLink }}" literally --> <!-- <a href="{{ googleLink }}">Google (Incorrect)</a> -->
<!-- Correct: using v-bind --> <a v-bind:href="googleLink" target="_blank">Google (v-bind)</a> <br>
<!-- Correct: using shorthand : --> <a :href="yahooLink" target="_blank">Yahoo (shorthand)</a> <br>
<!-- Binding an element's ID --> <p :id="paragraphId">This paragraph has a dynamic ID.</p>
<!-- Conditionally disabling a button --> <button :disabled="isButtonDisabled">{{ isButtonDisabled ? 'Disabled' : 'Enabled' }}</button> <button @click="toggleButton">Toggle Disable</button> </div>
<script> const { createApp, ref } = Vue;
createApp({ setup() { const googleLink = ref('https://www.google.com'); const yahooLink = ref('https://www.yahoo.com'); const paragraphId = ref('my-unique-paragraph'); const isButtonDisabled = ref(false);
function toggleButton() { isButtonDisabled.value = !isButtonDisabled.value; }
return { googleLink, yahooLink, paragraphId, isButtonDisabled, toggleButton }; } }).mount('#app-attr'); </script></body></html>v-bind:href or :href binds the anchor tag’s href attribute to the value of the googleLink or yahooLink reactive variable. Similarly, :id binds the paragraph’s ID, and :disabled dynamically binds the button’s disabled state.
Binding HTML Classes (v-bind:class or :class)
Section titled “Binding HTML Classes (v-bind:class or :class)”You can dynamically toggle classes by binding :class to an object or an array.
Object Syntax
Section titled “Object Syntax”Bind to an object where keys are class names and values are boolean expressions determining if the class should be applied.
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Vue 3 Class Binding (Object)</title> <script src="https://unpkg.com/vue@3"></script> <style> .active { background-color: lightgreen; font-weight: bold; } .text-danger { color: red; } .base-style { padding: 10px; border: 1px solid #ccc; margin-top: 10px; } </style></head><body> <div id="app-class-obj"> <div class="base-style" :class="{ active: isActive, 'text-danger': hasError }"> This div's classes change dynamically. </div> <button @click="isActive = !isActive">Toggle Active</button> <button @click="hasError = !hasError">Toggle Error</button>
<!-- Can also bind to a computed property returning an object --> <div class="base-style" :class="classObject"> Bound to computed object. </div> </div>
<script> const { createApp, ref, computed } = Vue;
createApp({ setup() { const isActive = ref(true); const hasError = ref(false);
// Computed property returning the class object const classObject = computed(() => ({ active: isActive.value, 'text-danger': hasError.value // You can add more static or dynamic classes here }));
return { isActive, hasError, classObject }; } }).mount('#app-class-obj'); </script></body></html>The active class is applied only when isActive is true, and text-danger only when hasError is true. Note that kebab-cased class names like text-danger need quotes in the object key. You can mix static (base-style) and dynamic classes.
Array Syntax
Section titled “Array Syntax”Bind to an array containing class names (strings) or objects (using the object syntax).
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Vue 3 Class Binding (Array)</title> <script src="https://unpkg.com/vue@3"></script> <style> .active { background-color: lightblue; } .important { font-weight: bold; border: 2px solid blue; } .base { padding: 15px; margin-top: 10px; } </style></head><body> <div id="app-class-arr"> <div :class="['base', 'important', { active: isActive }]"> Mixing array and object syntax. </div> <button @click="isActive = !isActive">Toggle Active</button>
<!-- Binding to a computed property returning an array --> <div :class="classArray"> Bound to computed array. </div> </div>
<script> const { createApp, ref, computed } = Vue;
createApp({ setup() { const isActive = ref(false); const activeClass = ref('active'); // Class name in a variable const importantClass = ref('important');
const classArray = computed(() => [ 'base', importantClass.value, // Dynamically get class name isActive.value ? activeClass.value : '' // Conditional class ]);
return { isActive, classArray }; } }).mount('#app-class-arr'); </script></body></html>This applies the base and important classes always, and the active class conditionally based on isActive. You can use ternary operators or include objects within the array.
With Components
Section titled “With Components”When using :class on a custom component, the classes will be added to the component’s root element, merging with any existing classes on that root element.
Binding Inline Styles (v-bind:style or :style)
Section titled “Binding Inline Styles (v-bind:style or :style)”Bind :style to an object or an array of objects.
Object Syntax
Section titled “Object Syntax”The object syntax is recommended. CSS property names can use camelCase or kebab-case (use quotes for kebab-case).
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Vue 3 Style Binding (Object)</title> <script src="https://unpkg.com/vue@3"></script></head><body> <div id="app-style-obj"> <!-- Direct object binding --> <div :style="{ color: activeColor, fontSize: fontSize + 'px', 'margin-top': '10px' }"> Style bound directly. </div>
<!-- Binding to a data object --> <div :style="styleObject"> Style bound to data object. </div>
<label>Color:</label> <input v-model="activeColor"> <label>Font Size (px):</label> <input type="range" v-model="fontSize" min="10" max="40"> </div>
<script> const { createApp, ref, computed } = Vue;
createApp({ setup() { const activeColor = ref('blue'); const fontSize = ref(16);
// Computed property returning the style object const styleObject = computed(() => ({ color: activeColor.value, fontSize: `${fontSize.value}px` // Use template literal // backgroundColor: 'lightyellow' // Add more styles }));
return { activeColor, fontSize, styleObject }; } }).mount('#app-style-obj'); </script></body></html>The text color and font size are dynamically controlled by the activeColor and fontSize variables.
Array Syntax
Section titled “Array Syntax”You can bind :style to an array of multiple style objects. This is useful for applying styles from several sources.
<div id="app-style-arr"> <div :style="[baseStyles, overrideStyles]"> Style bound to array of objects. </div></div>
<script> const { createApp, ref } = Vue; createApp({ setup() { const baseStyles = ref({ fontWeight: 'bold', padding: '10px' }); const overrideStyles = ref({ color: 'green', border: '1px solid green' }); return { baseStyles, overrideStyles }; } }).mount('#app-style-arr');</script>Styles from overrideStyles will merge with and potentially overwrite styles in baseStyles if they target the same properties.
Vue automatically adds vendor prefixes (like -webkit-) where needed for CSS properties bound via :style.
Form Input Bindings (v-model)
Section titled “Form Input Bindings (v-model)”The v-model directive creates two-way data binding on form inputs (<input>, <textarea>, <select>). It automatically picks the correct way to update the element based on the input type.
Example: Text, Textarea, Checkbox, Radio, Select
Section titled “Example: Text, Textarea, Checkbox, Radio, Select”<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Vue 3 v-model Example</title> <script src="https://unpkg.com/vue@3"></script> <style> form > div { margin-bottom: 15px; } label { margin-right: 10px; } </style></head><body> <div id="app-v-model"> <form @submit.prevent> <!-- Text Input --> <div> <label for="name">Name:</label> <input type="text" id="name" v-model="formData.name" placeholder="Enter name"> <p>Entered Name: {{ formData.name }}</p> </div>
<!-- Textarea --> <div> <label for="message">Message:</label> <textarea id="message" v-model="formData.message" placeholder="Enter message"></textarea> <p style="white-space: pre-line;">Entered Message: {{ formData.message }}</p> </div>
<!-- Single Checkbox (Boolean) --> <div> <input type="checkbox" id="agree" v-model="formData.agreed"> <label for="agree">Agree to terms</label> <p>Agreed: {{ formData.agreed }}</p> </div>
<!-- Multiple Checkboxes (Array) --> <div> <span>Interests:</span> <input type="checkbox" id="tech" value="Technology" v-model="formData.interests"> <label for="tech">Technology</label> <input type="checkbox" id="music" value="Music" v-model="formData.interests"> <label for="music">Music</label> <input type="checkbox" id="sports" value="Sports" v-model="formData.interests"> <label for="sports">Sports</label> <p>Selected Interests: {{ formData.interests }}</p> </div>
<!-- Radio Buttons --> <div> <span>Favorite Color:</span> <input type="radio" id="red" value="Red" v-model="formData.favoriteColor"> <label for="red">Red</label> <input type="radio" id="green" value="Green" v-model="formData.favoriteColor"> <label for="green">Green</label> <p>Selected Color: {{ formData.favoriteColor }}</p> </div>
<!-- Select Dropdown --> <div> <label for="country">Country:</label> <select id="country" v-model="formData.country"> <option disabled value="">Please select one</option> <option>USA</option> <option>Canada</option> <option>Mexico</option> </select> <p>Selected Country: {{ formData.country }}</p> </div> <!-- Select Multiple (Array) --> <div> <label for="options">Options (Multiple):</label> <select id="options" v-model="formData.selectedOptions" multiple> <option value="A">Option A</option> <option value="B">Option B</option> <option value="C">Option C</option> </select> <p>Selected Options: {{ formData.selectedOptions }}</p> </div>
</form> </div>
<script> const { createApp, reactive } = Vue;
createApp({ setup() { const formData = reactive({ name: '', message: '', agreed: false, interests: [], // Array for multiple checkboxes favoriteColor: 'Red', // Initial radio selection country: '', // Initial select value selectedOptions: [] // Array for multiple select });
return { formData }; } }).mount('#app-v-model'); </script></body></html>Explanation
Section titled “Explanation”v-modelsyncs the form element’s value with the corresponding property informData.- For text inputs and textareas, it uses the
valueproperty andinputevent. - For checkboxes, it uses the
checkedproperty andchangeevent. A single checkbox binds to a boolean, while multiple checkboxes with the samev-modelbind to an array of theirvalueattributes. - For radio buttons, it uses the
checkedproperty andchangeevent, binding to the selected radio’svalue. - For select fields, it uses
valueandchange. A single select binds to the selected option’s value. A multiple select binds to an array of selected option values.
v-model Modifiers
Section titled “v-model Modifiers”v-model has built-in modifiers:
- .lazy: Syncs after
changeevents instead ofinput(e.g., update when focus leaves the input, not on every keystroke). - .number: Automatically typecasts the input value to a number. If the value cannot be parsed, the original value is returned.
- .trim: Automatically trims whitespace from the user input.
<input v-model.lazy="message"> <!-- Updates when input loses focus --><input v-model.number="age" type="number"> <!-- Ensures age is a number --><input v-model.trim="username"> <!-- Removes leading/trailing whitespace -->Data binding is a cornerstone of Vue, enabling seamless synchronization between your application state and the user interface.