← Back to all tutorials

Custom Property Binding (& @Input)

Pass data from parent to child components using @Input — custom property binding for reusable components.

Custom Property Binding (& @Input)

@Input() lets a parent component pass data down to a child component via property binding. This is how you make components reusable and configurable.

Defining an @Input

// child: user-card.component.ts
import { Component, Input } from '@angular/core';

@Component({
    selector: 'app-user-card',
    template: `
        <div class="card">
            <h3>{{ name }}</h3>
            <p>{{ role }}</p>
            <span [class.online]="isOnline">
                {{ isOnline ? 'Online' : 'Offline' }}
            </span>
        </div>
    `
})
export class UserCardComponent {
    @Input() name: string = '';
    @Input() role: string = 'Viewer';
    @Input() isOnline: boolean = false;
}

Passing Data from Parent

// parent: app.component.ts
export class AppComponent {
    userName = 'Alice Johnson';
    userRole = 'Developer';
    userOnline = true;
}

// parent template:
<app-user-card 
    [name]="userName"
    [role]="userRole"
    [isOnline]="userOnline">
</app-user-card>

<!-- Static values (no binding, just strings): -->
<app-user-card 
    name="Bob Smith"
    role="Designer"
    [isOnline]="false">
</app-user-card>

Passing Objects

// child component
export class UserCardComponent {
    @Input() user!: { name: string; role: string; isOnline: boolean };
}

// child template
<div class="card">
    <h3>{{ user.name }}</h3>
    <p>{{ user.role }}</p>
</div>

// parent
export class AppComponent {
    currentUser = { name: 'Alice', role: 'Admin', isOnline: true };
}

// parent template
<app-user-card [user]="currentUser"></app-user-card>

Using with *ngFor

// parent
export class AppComponent {
    users = [
        { name: 'Alice', role: 'Admin', isOnline: true },
        { name: 'Bob', role: 'Designer', isOnline: false },
        { name: 'Carol', role: 'Developer', isOnline: true },
    ];
}

// parent template — render a card for each user!
<app-user-card 
    *ngFor="let user of users"
    [name]="user.name"
    [role]="user.role"
    [isOnline]="user.isOnline">
</app-user-card>

Input with Alias

// The property name inside the component can differ from the binding name:
@Input('cardTitle') title: string = '';

// Parent uses the alias:
<app-card [cardTitle]="'My Card'"></app-card>

Responding to Input Changes

import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';

export class UserCardComponent implements OnChanges {
    @Input() name: string = '';

    ngOnChanges(changes: SimpleChanges): void {
        if (changes['name']) {
            console.log('Name changed from', 
                changes['name'].previousValue, 
                'to', changes['name'].currentValue);
        }
    }
}

Data Flow Direction

Parent Component
    │
    │  [name]="userName"   (property binding)
    │  [role]="userRole"
    ▼
Child Component (@Input properties)

Key Takeaways

  • @Input() marks a property as receivable from a parent component
  • Parent uses [propertyName]="value" to pass data down
  • Works with primitives, objects, arrays — any data type
  • Combine with *ngFor to render lists of configurable components
  • Use ngOnChanges to react when input values change
  • Data flows one-way: parent → child