Two way binding is a shorthand to simultaneously bind a value into an element, while also giving that element the ability to propagate changes back through this binding.
The syntax for two-way binding is a combination of square brackets and parentheses, [()]. It combines the syntax from property binding, [], and the syntax from event binding, (). The Angular community informally refers to this syntax as "banana-in-a-box".
Developers commonly use two-way binding to keep component data in sync with a form control as a user interacts with the control. For example, when a user fills out a text input, it should update the state in the component.
The following example dynamically updates the firstName attribute on the page:
import {Component} from '@angular/core';
import {FormsModule} from '@angular/forms';
@Component({
imports: [FormsModule],
template: `
<main>
<h2>Hello {{ firstName }}!</h2>
<input type="text" [(ngModel)]="firstName" />
</main>
`,
})
export class App {
firstName = 'Ada';
}
To use two-way binding with native form controls, you need to:
FormsModule from @angular/forms
ngModel directive with the two-way binding syntax (e.g., [(ngModel)])firstName)Once that is set up, Angular will ensure that any updates in the text input will reflect correctly inside of the component state!
Learn more about NgModel in the official docs.
Leveraging two-way binding between a parent and child component requires more configuration compared to form elements.
Here is an example where the App is responsible for setting the initial count state, but the logic for updating and rendering the UI for the counter primarily resides inside its child Counter.
// ./app.ts
import {Component} from '@angular/core';
import {Counter} from './counter';
@Component({
selector: 'app-root',
imports: [Counter],
template: `
<main>
<h1>Counter: {{ initialCount }}</h1>
<app-counter [(count)]="initialCount"></app-counter>
</main>
`,
})
export class App {
initialCount = 18;
}
// './counter.ts';
import {Component, model} from '@angular/core';
@Component({
selector: 'app-counter',
template: `
<button (click)="updateCount(-1)">-</button>
<span>{{ count() }}</span>
<button (click)="updateCount(+1)">+</button>
`,
})
export class Counter {
count = model<number>(0);
updateCount(amount: number): void {
this.count.update((currentCount) => currentCount + amount);
}
} If we break down the example above to its core, each two-way binding for components requires the following:
The child component must contain a model property.
Here is a simplified example:
// './counter.ts';
import {Component, model} from '@angular/core';
@Component({
/* Omitted for brevity */
})
export class Counter {
count = model<number>(0);
updateCount(amount: number): void {
this.count.update((currentCount) => currentCount + amount);
}
}
The parent component must:
model property name in the two-way binding syntax.model property.Here is a simplified example:
// ./app.ts
import {Component} from '@angular/core';
import {Counter} from './counter';
@Component({
selector: 'app-root',
imports: [Counter],
template: `
<main>
<app-counter [(count)]="initialCount"></app-counter>
</main>
`,
})
export class App {
initialCount = 18;
}
Super-powered by Google ©2010–2025.
Code licensed under an MIT-style License. Documentation licensed under CC BY 4.0.
https://angular.dev/guide/templates/two-way-binding