AngularJSProperty Binding

Property Binding in Angular

Property binding lets you set the value of a DOM element property or a child component's @Input property from your component's TypeScript class. The square-bracket syntax [property]="expression" tells Angular to evaluate the right-hand side as a live TypeScript expression rather than a static string.

Property binding is a one-way flow: data travels from the component class to the template.

Basic Syntax

TS
@Component({
  selector: 'app-image',
  standalone: true,
  template: `
    <!-- Without binding (static string) -->
    <img src="logo.png" alt="Logo" />

    <!-- With binding (dynamic expression) -->
    <img [src]="logoUrl" [alt]="logoAlt" />
  `,
})
export class ImageComponent {
  logoUrl = '/assets/logo.png';
  logoAlt = 'Company Logo';
}
Note
The key difference: \`src="logo.png"\` is a static HTML attribute. \`[src]="logoUrl"\` evaluates \`logoUrl\` as a TypeScript expression each change detection cycle.
Binding to DOM Properties

Almost any DOM property can be bound. The property name on the left is the JavaScript DOM property name, not the HTML attribute name (they usually match but not always).

TS
@Component({
  selector: 'app-form-demo',
  standalone: true,
  template: `
    <!-- Boolean properties -->
    <button [disabled]="isSubmitting">Submit</button>
    <input [readonly]="isReadOnly" [value]="defaultValue" />

    <!-- String properties -->
    <a [href]="profileUrl">View Profile</a>
    <img [src]="avatarUrl" [alt]="userName + ' avatar'" />

    <!-- Numeric properties -->
    <progress [value]="uploadProgress" [max]="100"></progress>

    <!-- innerHTML (use with caution) -->
    <div [innerHTML]="trustedHtml"></div>
  `,
})
export class FormDemoComponent {
  isSubmitting = false;
  isReadOnly = true;
  defaultValue = 'John Doe';
  profileUrl = '/profile/123';
  avatarUrl = 'https://example.com/avatar.jpg';
  userName = 'Jane';
  uploadProgress = 65;
  trustedHtml = '<strong>Formatted</strong> content';
}
Warning
Binding to \`[innerHTML]\` can expose your app to XSS attacks if the content comes from user input. Angular does sanitize the value, but prefer template interpolation or structural directives over \`innerHTML\` whenever possible.
Binding to Component @Input Properties

Property binding is also how you pass data to child components. The child declares an @Input() property; the parent binds to it with square brackets.

TS
// progress-bar.component.ts (child)
import { Component, Input } from '@angular/core';

@Component({
  selector: 'app-progress-bar',
  standalone: true,
  template: `
    <div class="progress-track">
      <div
        class="progress-fill"
        [style.width.%]="value"
        [class.complete]="value >= 100"
      ></div>
    </div>
    <span>{{ value }}%</span>
  `,
})
export class ProgressBarComponent {
  @Input() value = 0;
  @Input() label = '';
}

TS
// parent component
@Component({
  selector: 'app-dashboard',
  standalone: true,
  imports: [ProgressBarComponent],
  template: `
    <app-progress-bar [value]="downloadProgress" [label]="'Download'" />
    <app-progress-bar [value]="uploadProgress" [label]="'Upload'" />
  `,
})
export class DashboardComponent {
  downloadProgress = 72;
  uploadProgress = 45;
}
Attribute Binding vs Property Binding

HTML attributes initialise the DOM; JavaScript properties are the live state. They often share names but not always. When a property does not exist on the DOM element, use [attr.name].

Situation

Syntax

Example

DOM property exists

[property]

[disabled]="bool"

HTML attribute only (no matching property)

[attr.name]

[attr.colspan]="3"

ARIA attributes

[attr.aria-*]

[attr.aria-label]="label"

SVG attributes

[attr.name]

[attr.viewBox]="vb"

Data attributes

[attr.data-*]

[attr.data-id]="id"

HTML
<!-- colspan has no corresponding DOM property — use attr. -->
<td [attr.colspan]="columnSpan">Merged</td>

<!-- ARIA attributes -->
<button [attr.aria-expanded]="isOpen" [attr.aria-label]="buttonLabel">
  Toggle
</button>

<!-- SVG viewBox -->
<svg [attr.viewBox]="viewBox">
  <circle [attr.cx]="cx" [attr.cy]="cy" [attr.r]="radius" />
</svg>
Class Binding

Angular offers three syntaxes for binding CSS classes dynamically.

TS
@Component({
  selector: 'app-status',
  standalone: true,
  template: `
    <!-- Single class toggle -->
    <div [class.active]="isActive">Single toggle</div>

    <!-- Multiple classes with object map -->
    <div [ngClass]="{
      'btn-primary': isPrimary,
      'btn-lg': isLarge,
      'disabled': !isEnabled
    }">Multi-class</div>

    <!-- Classes from an array -->
    <div [ngClass]="['card', cardType, cardSize]">Array classes</div>

    <!-- Classes from a computed string -->
    <div [class]="computedClasses">Dynamic classes</div>
  `,
})
export class StatusComponent {
  isActive = true;
  isPrimary = true;
  isLarge = false;
  isEnabled = true;
  cardType = 'card-outlined';
  cardSize = 'card-lg';

  get computedClasses(): string {
    return [
      'base-class',
      this.isActive ? 'active' : 'inactive',
    ].join(' ');
  }
}
Style Binding

Inline styles can be bound using [style.property] or the object-map form [ngStyle].

TS
@Component({
  selector: 'app-theme-demo',
  standalone: true,
  template: `
    <!-- Single style property -->
    <p [style.color]="textColor">Colored text</p>
    <p [style.font-size.px]="fontSize">Sized text</p>
    <div [style.width.%]="widthPercent">Width percent</div>

    <!-- Multiple styles via object map -->
    <div [ngStyle]="{
      'background-color': bgColor,
      'border-radius.px': borderRadius,
      opacity: opacity
    }">Styled box</div>
  `,
})
export class ThemeDemoComponent {
  textColor = '#d63384';
  fontSize = 18;
  widthPercent = 75;
  bgColor = '#f8f9fa';
  borderRadius = 8;
  opacity = 0.9;
}
Tip
Prefer CSS classes and \`[class]\` bindings over inline \`[style]\` bindings where possible. Classes are easier to maintain, reuse, and theme.
One-Time vs Reactive Bindings

All property bindings are reactive by default: Angular re-evaluates the expression on every change detection cycle. If a value will never change after initialisation, you can signal this with a one-time binding using the @ prefix (not standard Angular, but the pattern exists in templates via signals).

In modern Angular, signals make this explicit:

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

@Component({
  selector: 'app-signal-binding',
  standalone: true,
  template: `
    <!-- Signal-based property binding — only re-renders when signal changes -->
    <img [src]="avatarUrl()" [alt]="userName()" />
    <p [style.color]="themeColor()">{{ greeting() }}</p>
  `,
})
export class SignalBindingComponent {
  userName = signal('Alice');
  avatarUrl = signal('/assets/alice.png');
  themeColor = signal('#007bff');

  greeting = computed(() => `Hello, ${this.userName()}!`);
}
Common Property Binding Patterns

Binding

Purpose

[src]="url"

Dynamic image source

[href]="link"

Dynamic anchor link

[disabled]="bool"

Enable / disable form controls

[hidden]="bool"

Hide element (keeps in DOM)

[value]="val"

Set input value

[checked]="bool"

Checkbox state

[selected]="bool"

Option selected state

[placeholder]="text"

Input placeholder

[class.name]="bool"

Toggle a CSS class

[style.prop]="val"

Set one inline style

[attr.x]="val"

Set arbitrary HTML attribute

Summary
  • Square brackets [property]="expr" evaluate expr as TypeScript — not a plain string.

  • Bind any DOM property: src, href, disabled, value, checked, innerHTML, etc.

  • Bind to child @Input properties the same way.

  • Use [attr.name] for attributes that have no DOM property equivalent (colspan, aria-*, SVG).

  • Use [class.name] or [ngClass] to toggle CSS classes dynamically.

  • Use [style.prop] or [ngStyle] to set inline styles dynamically.

  • Signals make property bindings fine-grained and efficient in Angular 17+.