Events and Forms

By Syncfusion®, Inc. · Last updated

v-on and @, method and inline handlers, $event, key aliases, system keys, .exact and event modifiers, then v-model on every control, value bindings, .lazy, .number and .trim, submit and reset, validation rules, error messages, accessible errors with useId() and validation libraries.

Events

  • An event = something that happens on the page: a click, a key press, a mouse move.
  • v-on listens for an event and runs your code when it happens.
  • Its short form is @. v-on:click and @click are the same.
  • Your code usually changes state. Vue then updates the screen.

Simple lesson: @event="code" runs code when the event happens.

A Real-World Example

  • Meera's counter has buttons for each dish.
  • Each button adds a different number of plates.
  • One method handles all buttons. Each button passes its own numbers.

What You Will Learn

  1. How to write inline handlers and method handlers, with arguments and $event.
  2. How to listen to mouse and keyboard events, key aliases and system keys.
  3. How event modifiers like .stop, .prevent and .once work.
  4. How v-model links a form control and a ref both ways.
  5. How to use v-model on every kind of control, with value bindings.
  6. The .lazy, .number and .trim modifiers.
  7. How to submit and reset a form without a page reload.
  8. How to validate input and turn off the submit button.
  9. How to make errors clear for screen readers.

Inline and Method Handlers

  • Inline handler = a short piece of code: @click="count++".
  • Method handler = the name of a function: @click="addOrder".
  • A method handler gets the event object as its first argument.
  • Event object = details about the event, such as which element was clicked.

Arguments and $event

  • Call the method with arguments: @click="add(2)".
  • Then the event object is not passed by itself.
  • Need both? Pass $event as an argument: @click="add(2, $event)".
  • You can also run two things: @click="one(); two()".

Simple lesson: pass arguments in brackets. Add $event when you also need the event.

Name handlers after what they do, such as addOrder or openMenu, not after the event, such as onClick. The template then reads like a sentence.

Mouse and Keyboard Events

  • Common mouse events: click, dblclick, mouseenter, mouseleave, contextmenu.
  • Common keyboard events: keydown and keyup.
  • Key alias = a modifier that picks one key: @keyup.enter.
  • Vue has aliases for .enter, .tab, .delete, .esc, .space, .up, .down, .left and .right.
  • You can also use any key name in kebab-case, such as .page-down.

System Keys and .exact

  • System keys = .ctrl, .alt, .shift and .meta (⌘ on Mac, ⊞ on Windows).
  • @click.ctrl runs only if Ctrl is held during the click.
  • @click.ctrl still runs if Shift is held too.
  • .exact means "these keys and no others". @click.exact = no system key at all.

console is one of the safe globals a template may use, so the handlers above can log straight from the template. In bigger components, call a script function instead. It is easier to read and test.

Simple lesson: add .enter, .esc and friends for keys, and .ctrl or .exact for system keys.

Event Modifiers

  • Event modifier = a dot word that changes how the event behaves.
  • .stop = stop the event from reaching parent elements. Same as event.stopPropagation().
  • .prevent = stop the browser's default action, like reloading on a form submit.
  • .self = run only if this exact element was clicked, not a child.
  • .capture = run on the way down, before the children.
  • .once = run one time only.
  • .passive = tell the browser you will not call preventDefault. It makes scrolling smoother.

Animation: a click on a button inside a card inside the page. The event travels down in the capture phase, reaches the button, then bubbles up to the card and the page. With .stop on the button, it stops at the button

page (div)

card (div)

button

1. capture: down to the target 2. target: the button's handler 3. bubble: up to card, then page

Events go down (capture), hit the target, then bubble up. .stop ends the trip.

  • What happened: "Like" logged twice, because the click bubbled to the card.
  • "Save" logged once, because .stop stopped it.
  • "Send" did not reload the page, because of .prevent.

Without .prevent, a form submit reloads the page and you lose all your state. Always write @submit.prevent on Vue forms.

Chaining Modifiers

  • You can chain modifiers: @click.stop.prevent.
  • Order matters. @click.prevent.self prevents every click. @click.self.prevent prevents only clicks on the element itself.
  • Do not use .passive and .prevent together. The browser ignores .prevent and warns.

Mouse Button Modifiers

  • .left, .right and .middle pick a mouse button.
  • @click.right does not exist as a normal click. Use @contextmenu or @mouseup.right.
  • Add .prevent to stop the browser's own right-click menu.

Simple lesson: modifiers change how an event behaves. .prevent and .stop are the ones you will use most.

Forms in Vue

  • Forms collect data: names, phone numbers, choices.
  • Without Vue, you read each box by hand when the form is sent.
  • v-model links a form control and a ref both ways.
  • Two-way binding = typing changes the ref, and changing the ref changes the box.
  • v-model ignores value, checked and selected written in the HTML. The ref is the only source of the start value.
  • For languages typed with an input method (IME), the ref updates when a word is finished, not on every key.

Simple lesson: v-model keeps a form control and your state the same, both ways.

In Practice: a Booking Form

  • Meera takes table bookings online.
  • She needs a name, the number of guests and a time.
  • The summary below the form must update while people type.

How v-model Works

  • v-model="name" on a text box does two jobs:

    • it sets the box's value from name
    • it updates name on every input event
  • It is short for :value="name" @input="name = $event.target.value".

Animation: typing in the input sends the text to the ref through the input event, and changing the ref sends the value back to the input through the value binding

input box Asha Ravi

const name = ref("") "Asha" "Ravi"

@input :value

You type "Asha": the ref changes. The code sets "Ravi": the box changes.

v-model is a value binding plus an input listener.

Simple lesson: v-model = :value + @input, written once.

v-model on Every Control

  • Text box and text area: binds the text.
  • One checkbox: binds true or false.
  • Many checkboxes with one array: the array holds the value of each ticked box.
  • Radio buttons: binds the value of the chosen one.
  • Select: binds the chosen option. Add multiple to bind an array.

v-model ignores the value, checked and selected attributes written in the HTML. The ref is the one source of truth. Set the starting value in the script.

Value Bindings

  • By default a checkbox gives true or false, and a radio or option gives its text.
  • true-value and false-value change what one checkbox gives.
  • :value gives any JavaScript value, such as a number or an object.

Simple lesson: use :value, true-value and false-value when you need more than text.

Modifiers

  • .lazy = update on change (when you leave the box), not on every key.
  • .number = turn the text into a number. Text that is not a number stays text.
  • On <input type="number">, Vue applies .number for you.
  • .trim = remove spaces at the start and the end.
  • What happened: the city updated only after you left the box.
  • plates + 1 did maths, not text joining.
  • The coupon lost its outer spaces.

Simple lesson: .lazy waits, .number makes numbers, .trim cuts spaces.

.number gives back the text when it cannot read a number, such as an empty box. Check with typeof or validation before doing maths with it.

Submitting and Resetting

  • Listen with @submit.prevent on the <form>, so the page does not reload.
  • Read the refs. They already hold every value.
  • To reset, put the starting values back into the refs.
  • A reactive object is handy for many fields. Reset it with Object.assign.

Simple lesson: @submit.prevent, read the state, then reset it.

Validation

  • Validation = checking input before you accept it.
  • Common rules:

    • required: not empty
    • length: at least or at most some letters
    • pattern: matches a shape, such as 10 digits
    • numeric: a number in a range
    • custom: any rule you write, such as "not on Monday"
  • Keep the errors in a computed. They update while people type.
  • Turn the submit button off while there are errors.

Show an error only after the person has touched a field, or tried to submit. Red text on an empty form before anyone types feels unfriendly. Keep a touched flag per field, set on @blur.

Accessible Errors

  • A screen reader must know a field is wrong and why.
  • aria-invalid="true" marks the field as wrong.
  • aria-describedby="id" links the field to its error text.
  • Ids must be unique on the page. useId() (Vue 3.5) makes one for you.

Validation Libraries

  • Big forms use a library, so you do not write every rule by hand.
  • VeeValidate = a Vue form library: fields, rules, touched state and errors.
  • Zod = describes the shape of data once, then checks it.
  • They are installed with npm in a real project. This course writes rules by hand to show the idea.
// A real project: npm install vee-validate zod @vee-validate/zod
import { useForm } from "vee-validate";
import { toTypedSchema } from "@vee-validate/zod";
import { z } from "zod";

const { errors, defineField } = useForm({
  validationSchema: toTypedSchema(
    z.object({ phone: z.string().regex(/^\d{10}$/, "Enter a 10-digit phone number.") }),
  ),
});

Simple lesson: keep errors in a computed, disable submit while there are errors, and link each error to its field.

TL;DR

  • @click="code" = short for v-on:click. Runs code on a click.
  • $event = the event object, when you also pass arguments.
  • Key alias = @keyup.enter, .esc, .space, .up ...
  • .stop = stop bubbling to parents.
  • .prevent = stop the browser's default action.
  • v-model = two-way binding: :value plus @input.
  • .lazy / .number / .trim = on change / as a number / no outer spaces.
  • Validation = errors in a computed, :disabled="!valid".
  • Accessible errors = aria-invalid, aria-describedby, useId().

Common mistakes

MistakeWrong ideaCorrect ideaWhat goes wrong
@click="add()" then reading the eventThe event is still passedPass $event: add($event)The event argument is undefined
Form without .preventVue stops the reloadWrite @submit.preventThe page reloads and state is lost
Inner button triggers the cardClicks stay on the buttonAdd .stop on the inner buttonTwo handlers run
@click.ctrl fires with Ctrl+ShiftIt means Ctrl onlyAdd .exactThe handler runs on extra key combos
value="..." with v-modelThe HTML value is the start valueSet the start value in the refThe attribute is ignored
No .numberA number input gives a numberAdd .number2 + 1 becomes "21"
Checkboxes with a string refMany boxes fill a stringUse an array refOnly true or false is stored
No .prevent on submitVue stops the reload@submit.preventThe page reloads and the form clears
Errors shown before typingShow every error at onceWait for blur or a submit tryAn unfriendly wall of red

Check Yourself

Exercises

What to Remember

  • @event listens. Use a method name, or a call with arguments.
  • Add $event when you pass arguments and still need the event.
  • Key aliases and system keys pick exact keys. .exact rules out the rest.
  • v-model binds a control and a ref both ways.
  • Many checkboxes need an array. Use :value for non-text values.
  • .number for numbers, .trim for clean text, .lazy to wait for change.

Next: Components and Single-File Components