Skip to content
Angular ng templates 4 min read

Event Binding

Event binding lets your template react to user interactions and DOM events — clicks, key presses, form input, focus changes, and any native or custom event. Where property binding pushes data into the DOM, event binding pulls signals out of it, wiring user actions to component logic. In modern Angular this is the foundation of interactivity, and it pairs naturally with signals to drive reactive state updates.

The (event) syntax

You bind to an event by wrapping the target event name in parentheses on the left of the assignment, and putting a template statement on the right. The statement runs every time the event fires.

<button (click)="increment()">Add one</button>

The name inside the parentheses is the DOM event name — click, input, keyup, submit, mouseenter, and so on. The right-hand side is a template statement: typically a method call, but it can also be an assignment or a small expression. Unlike interpolation, statements may have side effects.

import { Component, signal } from '@angular/core';

@Component({
  selector: 'app-counter',
  standalone: true,
  template: `
    <p>Count: {{ count() }}</p>
    <button (click)="increment()">Add one</button>
    <button (click)="count.set(0)">Reset</button>
  `,
})
export class CounterComponent {
  count = signal(0);

  increment(): void {
    this.count.update((n) => n + 1);
  }
}

Note the second button calls count.set(0) inline — perfectly valid as a template statement. Keep inline statements short; move anything non-trivial into a method.

Accessing the event with $event

Every event handler has access to a special variable named $event, which is the payload the DOM (or a child component) emits. For native DOM events this is the standard event object, so you get full type information when you cast the target.

import { Component, signal } from '@angular/core';

@Component({
  selector: 'app-search',
  standalone: true,
  template: `
    <input
      type="text"
      placeholder="Type to search"
      (input)="onInput($event)"
    />
    <p>You typed: {{ term() }}</p>
  `,
})
export class SearchComponent {
  term = signal('');

  onInput(event: Event): void {
    const input = event.target as HTMLInputElement;
    this.term.set(input.value);
  }
}

Because event.target is typed as the broad EventTarget, you cast it to the concrete element (HTMLInputElement) to read value. For keyboard events the object is a KeyboardEvent, so $event.key, $event.code, and modifier flags like $event.ctrlKey are available.

Tip: Avoid the pattern (input)="term.set($event.target.value)". Angular’s template type-checking can’t narrow $event.target to an input element, and it produces a type error in strict mode. Cast inside a method instead.

Key event filters (pseudo-events)

For keyboard events Angular offers a convenient filtering syntax so you don’t have to inspect $event.key manually. You append the key name to the event using a dot.

<input (keyup.enter)="submit()" />
<input (keydown.escape)="cancel()" />
<input (keyup.control.s)="save($event)" />

The handler only fires when the named key (and any listed modifiers) match. This keeps templates declarative and removes boilerplate if (event.key === 'Enter') checks.

Common DOM events

BindingFires when$event type
(click)Element is clickedMouseEvent
(input)Input value changesEvent
(change)Value committed (blur/select)Event
(submit)A form is submittedSubmitEvent
(keyup) / (keydown)A key is released/pressedKeyboardEvent
(focus) / (blur)Element gains/loses focusFocusEvent
(mouseenter)Pointer enters elementMouseEvent

Preventing default behaviour

Because the statement runs real code, you can call preventDefault() or stopPropagation() directly on the event. This is common for form submission where you want to handle the data in TypeScript rather than reload the page.

import { Component } from '@angular/core';

@Component({
  selector: 'app-login-form',
  standalone: true,
  template: `
    <form (submit)="onSubmit($event)">
      <input name="email" #email />
      <button type="submit">Sign in</button>
    </form>
  `,
})
export class LoginFormComponent {
  onSubmit(event: SubmitEvent): void {
    event.preventDefault();
    console.log('Submitting without reload');
  }
}

Output:

Submitting without reload

Custom events from components

Event binding isn’t limited to DOM events. Child components expose output() emitters, and you bind to them with the same parentheses syntax. Here $event is whatever value the child emits.

import { Component, output } from '@angular/core';

@Component({
  selector: 'app-rating',
  standalone: true,
  template: `
    @for (star of [1, 2, 3, 4, 5]; track star) {
      <button (click)="rate.emit(star)">★ {{ star }}</button>
    }
  `,
})
export class RatingComponent {
  rate = output<number>();
}
<app-rating (rate)="onRate($event)" />
onRate(value: number): void {
  console.log(`User rated: ${value}`);
}

The parent receives the emitted number through $event, fully typed thanks to output<number>().

Best Practices

  • Keep template statements short — delegate any logic beyond a single set/update call to a component method.
  • Cast $event.target to the concrete element type (e.g. HTMLInputElement) inside a method rather than inline, to satisfy strict template type-checking.
  • Use key pseudo-events like (keyup.enter) instead of manual event.key comparisons for cleaner, declarative templates.
  • Type your handler parameters precisely (MouseEvent, KeyboardEvent, SubmitEvent) so the compiler verifies your usage.
  • Update state through signals (set/update) in handlers to keep change detection efficient and predictable.
  • Call event.preventDefault() in form (submit) handlers to take full control of the data flow.
Last updated June 14, 2026
Was this helpful?