Components

Angular @Input: Complete Guide

Learn how to use the Angular @Input decorator with all its many extra options, including the super-useful input transforms mechanism.

Angular @Input: Complete Guide — Components article by Angular University on Angular In Depth
Angular @Input: Complete Guide — Components article by Angular University on Angular In Depth
On this page · 12 sections

If you've worked with Angular, you've likely encountered the @Input decorator.

This decorator is fundamental to the framework, enabling data flow from a parent component down to a child component.

However, the full potential of this decorator often goes unnoticed. It includes several powerful features and configuration options introduced over time.

A key focus here will be input transforms, a feature that can often serve as a better alternative to input getters/setters or the @Attribute decorator.

Input transforms are also a great tool for simplifying templates, particularly for common patterns like boolean flags or numeric read-only properties.

This guide provides a comprehensive look at the @Input decorator, covering all its features and providing practical examples for each.

Table of Contents

  • The fundamentals of using @Input
  • Making inputs required
  • Using @Input with getters and setters
  • Creating input aliases
  • Implementing input transforms
  • Exploring built-in transforms: booleanAttribute and numberAttribute
  • Comparing @Input and @Attribute
  • Choosing between @Input and @Attribute
  • Conclusion

The fundamentals of using @Input

The @Input() decorator is used to designate a class property as an input for a component.

Its primary role is to facilitate the passing of data from a parent component to a child component.

Here's the most straightforward way to use the @Input decorator:

@Component({
  selector: "child",
  template: ` <p>{{ name }}</p> `,
})
export class ChildComponent {
  @Input() name: string;
}

In this example, the name property is marked as an input.

Consequently, a parent component can bind to this property using the standard property binding syntax:

@Component({
  selector: "parent",
  template: ` <child [name]="name" /> `,
})
export class ParentComponent {
  name = "John Doe";
}

When the value of the name property in the parent component is changed, that new value is automatically propagated to the child component through the @Input() decorator.

This mechanism is the essence of @Input.

Now, let's move beyond these basics and examine some of the more advanced features and configuration options available.

Making inputs required

Inputs are optional by default, meaning no error is thrown if a parent component omits them.

You can, however, enforce that an input is always provided by marking it as required:

@Component({
  selector: "app-child",
  template: ` <p>{{ name }}</p> `,
})
export class ChildComponent {
  @Input({
    required: true,
  })
  name: string;
}

In the code above, the name property is required, which means the parent component is obligated to provide a value for it.

If the parent component fails to supply a value, Angular will throw an error:

[ERROR] NG8008: Required input 'name' from component ChildComponent must be specified.

Using @Input with getters and setters

Let's explore some of the less common features of @Input, starting with its use with getters and setters.

The @Input decorator can be applied not only to class properties but also to getters:

@Component({
  selector: "app-child",
  template: ` <p>{{ name }}</p> `,
})
export class ChildComponent {
  private myCourses: Course[];

  @Input()
  get courses() {
    return this.myCourses;
  }

  set courses(courses: Course[]) {
    // you can add here some logic to modify the courses input variable, and create a derived value
    this.myCourses = courses;
  }
}

This is particularly useful when you need to apply a transformation to the incoming value.

We'll discuss a more modern approach to this problem later in the article.

First, let's complete our look at getter-based inputs.

In this example, the component has an input property called courses, which internally relies on a member variable named myCourses.

Here is how a parent component would set this input:

@Component({
  selector: "app-parent",
  template: ` <app-child [courses]="parentCourses"/> `,
})
export class ParentComponent {

    parentCourses : Course[] = // some initial value

}

Note that the parent component cannot directly set the myCourses property.

You might be curious about how the input's name is determined. It's derived from the name of the getter function, which is courses in this case.

Creating input aliases

The name of an input property can also be explicitly defined using an alias.

This can be done concisely as follows:

@Component({
  selector: "app-child",
  template: ` <p>{{ name }}</p> `,
})
export class ChildComponent {
  @Input("userName") name: string;
}

For instance, the name input property is aliased to userName in the example above.

Once the alias is set, the parent component will use it like this:

@Component({
  selector: "app-parent",
  template: ` <app-child [userName]="name" />`,
})
export class ParentComponent {
  name = "John Doe";
}

If you're using the alias in conjunction with other input options, it can be specified within the @Input configuration object:

@Component({
  selector: "app-child",
  template: ` <p>{{ name }}</p> `,
})
export class ChildComponent {
  @Input({
    alias: "userName",
    required: true,
  })
  name: string;
}

Implementing input transforms

As mentioned earlier, input transforms offer a more elegant solution than getters and setters for modifying input values.

This feature allows you to alter an input's value right before it's assigned to the component's property, achieving the same result as a setter but more directly.

This is achieved through the transform property of the @Input decorator:

@Component({
  selector: "app-child",
  template: ` <p>{{ name }}</p> `,
})
export class ChildComponent {
  @Input({
    transform: (value: string) => value.toUpperCase(),
  })
  name: string;
}

With this transform, any string passed to the name input will be immediately converted to upper case on assignment.

Here are some important points to keep in mind when creating input transforms:

  • Your transform function should be pure, meaning it should not produce any side effects.
  • Transforms should be efficient and avoid heavy computations.
  • While you can't apply transforms conditionally, you can certainly include conditional logic *inside* the transform function.

Exploring built-in transforms: booleanAttribute and numberAttribute

Beyond replacing getters and setters, input transforms are excellent for simplifying common scenarios like boolean or numeric properties.

Angular includes two built-in input transforms designed for these cases: booleanAttribute and numberAttribute.

These tools can significantly enhance the readability of your templates by reducing boilerplate.

For example, consider creating a boolean input property, such as a disabled flag:

@Component({
  selector: "app-child",
  template: ` <p>{{ name }}</p> `,
})
export class ChildComponent {
  @Input()
  disabled: boolean;
}

The challenge here is that setting the flag requires the use of an input expression ([]) in the parent template:

@Component({
  selector: "app-parent",
  template: ` <app-child [disabled]="true" /> `,
})
export class ParentComponent {}

It would be much more convenient for users of your component if the flag could be set like this instead:

@Component({
  selector: "app-child",
  template: ` <app-child disabled /> `,
})
export class ParentComponent {}

This minor change has a significant impact on the user experience, making the component feel much more like plain HTML.

In this case, the very presence of the disabled attribute signifies that the property should be true.

This style is arguably more readable and cleaner than using property bindings.

Without additional help, this simplified syntax wouldn't work as expected.

However, we can enable this behavior by using the booleanAttribute input transform:

@Component({
  selector: "app-child",
  template: ` <p>{{ name }}</p> `,
})
export class ChildComponent {
  @Input({
    transform: booleanAttribute,
  })
  disabled: boolean;
}

Now the disabled property works as intended: its mere presence (even without a value) sets it to true, while its absence sets it to false.

It's important to note that this doesn't break dynamic assignment; you can still use a [] expression if you need to set the property programmatically.

The numberAttribute built-in input transform

Now, let's turn our attention to numberAttribute, another useful built-in transform.

This transform converts an input's string value into a numeric type:

@Component({
  selector: "app-child",
  template: ` <p>{{ age }}</p> `,
})
export class ChildComponent {
  @Input({
    transform: numberAttribute,
  })
  age: number;
}

With this transform in place, the age property can be set using a simpler syntax:

@Component({
  selector: "app-parent",
  template: ` <app-child age="20" />`,
})
export class ParentComponent {}

Any string assigned to age will be converted to a number automatically. If the string cannot be converted, the value will be NaN.

Without this transform, we'd be dealing with more verbose syntax:

@Component({
  selector: "app-parent",
  template: ` <app-child [age]="20" />`,
})
export class ParentComponent {}

That approach functions correctly, but it feels overly complex for setting a simple numeric constant.

Transforms make the parent component template more concise and bring it closer to the feel of standard HTML.

Comparing @Input and @Attribute

The @Attribute decorator is another one that might look similar to @Input at first glance.

Historically, @Attribute was used for several use cases, many of which are now more appropriately solved with transforms.

Although they may appear alike, the two decorators serve fundamentally different purposes.

To grasp why both exist, it's crucial to understand a basic principle of how the DOM works.

Let's recall that a DOM element has two distinct sets of key-value pairs:

  • DOM attributes: These come from HTML markup. Their values are always strings, and they don't change once they are set.

  • DOM properties: These are the properties of the DOM node itself, similar to properties on any JavaScript object. They can be of any type and are capable of changing over time.

While the DOM does automatically sync some attribute/property pairs (like the value property on an input), this is not a general rule. For the most part, an attribute and a property with the same name are independent and don't reflect each other's changes.

How to use @Attribute

When working with a framework like Angular, you're primarily interacting with DOM properties rather than attributes.

You rarely need to access DOM attributes directly within a framework context, but they remain a core part of the DOM.

For those instances where you do, Angular offers a decorator to retrieve an attribute's static string value.

Here is an example demonstrating the use of @Attribute:

@Component({
  selector: "app-child",
  template: ` <p>{{ age }}</p> `,
})
export class ChildComponent {
  constructor(@Attribute("age") public age: string) {}
}

As you can see, the @Attribute decorator is exclusively used within a component's constructor function.

Here is how you would set the attribute:

@Component({
  selector: "app-parent",
  template: ` <app-child age="10" /> `,
})
export class ParentComponent {}

This code will inject the string "10" into the constructor of the component.

Because it's a DOM attribute, this value is a constant and will never change during the component's lifecycle.

If you ever need to read a static DOM attribute, this is the technique to use within Angular.

Choosing between @Input and @Attribute

In most situations, you should rely on properties rather than DOM attributes. Therefore, @Input is the correct choice for the vast majority of your use cases.

If your goal with @Attribute was to support a more concise syntax for boolean or numeric values, then input transforms are the better tool, as we've demonstrated.

With the advent of input transforms, the use cases for the @Attribute decorator are now fewer than they used to be.

I hope you found this post useful. To stay updated on new similar posts about Angular, please consider subscribing to our newsletter:

You’ll also receive the latest news from the Angular ecosystem.

If you are interested in a comprehensive exploration of Angular Core features like @Input, you might find the Angular Core Deep Dive Course valuable:

Angular @Input: Complete Guide — figure 1

Conclusion

This guide has taken a detailed look at the @Input decorator, examining every option it currently offers.

One of the most valuable features is input transforms, which not only allow for cleaner templates but also serve as a powerful alternative in several common scenarios.

With this feature, the reliance on input getters/setters and the @Attribute decorator is diminished.

Given their convenience and utility, it's a good idea to start using input transforms in your own projects.

Should you have any questions or remarks, please share them in the comment section below. I'm here to help!

AU
Angular University

Writes about RxJS, Components, Signals. Active 2015–2026.

All 79 articles →