The @ViewChild and @ViewChildren decorators in Angular provide access to child elements in the view DOM by setting up view queries. A view query is a requested reference to a child element within a component view which contains metadata of the element. The scope of these decorators is limited to the component view and its embedded child views. These decorators are especially helpful in instances where being able to access and modify elements within the view in conventional ways is not possible.
For example, if a library ships with a component or directive with a public non-input or non-output property you’d like to change, these decorators would allow you to access and modify them. These decorators are also helpful in exposing providers configured in child components to inject dependencies ( like services, configuration values, etc. ) that the main component may not have access to.
In this article, we will cover how to use the @ViewChild and @ViewChildren decorators, what their properties do, and how to specify their properties.
The Replay is a weekly newsletter for dev and engineering leaders.
Delivered once a week, it's your curated guide to the most important conversations around frontend dev, emerging AI tools, and the state of modern software.
The AfterViewInit lifecycle hook is called when the component view and its child views are completely initialized. So for immediate modifications or assignments, the best place to access view queries would be in the ngAfterViewInit callback because the view queries are already resolved and set. Trying to access them before ngAfterViewInit responds may generate undefined values. However, the @ViewChild decorator provides a static property that can be set to resolve a view query before change detection runs. We’ll cover how to use this property below.
This decorator takes three properties, a selector, a read, and a static property. The read and static properties are optional. These properties are specified like this:
@ViewChild(selector {read: readValue, static: staticValue}) property;
The selector property specifies what child element within the component view is to be queried. According to the @ViewChild documentation, five kinds of selectors are supported. These are:
1) Classes with @Component or @Directive decorators
In this first example, MenuItemComponent is a queried from the MenuComponent view:
@Component({
selector: 'menu-item',
template: `<p>{{menuText}}</p>`
})
export class MenuItemComponent {
@Input() menuText: string;
}
@Component({
selector: 'menu',
template: `<menu-item [menuText]="'Contact Us'"></menu-item>`
})
export class MenuComponent{
@ViewChild(MenuItemComponent) menu: MenuItem;
}
Here’s an example with a directive:
@Directive({
selector: '[textHighlight]'
})
export class TextHighlightDirective{}
@Component({
selector: 'profile',
template: '<p textHighlight>Some text to highlight</p>'
})
export class ProfileComponent{
@ViewChild(TextHighlightDirective) highlightedText: TextHighlightDirective;
}
2) A template reference variable as a string. Template reference variables are commonly used within templates but in this instance, it is used to configure a view query:
@Component({
selector: 'menu-item',
template: `<p>{{menuText}}</p>`
})
export class MenuItemComponent {
@Input() menuText: string;
}
@Component({
selector: 'menu',
template: `
<menu-item #aboutUs [menuText]="'About Us'"></menu-item>
<menu-item #contactUs [menuText]="'Contact Us'"></menu-item>
`
})
export class MenuComponent{
@ViewChild('aboutUs') aboutItem: MenuItem;
@ViewChild('contactUs') contactItem: MenuItem;
}
3) A provider defined in the child component tree of the current component. In this example, the SampleService is specified as a provider token for the FirstChildComponentClass. Since <first-child> is an element in the ParentComponent we can access the SampleService from it using the SampleService class as a token:
export class SampleService {}
@Component({
selector: 'first-child',
providers: [SampleService]
})
export class FirstChildComponent{}
@Component({
selector: 'parent',
template: '<first-child></first-child>'
})
export class ParentComponent{
@ViewChild(SampleService) sampleService: SampleService;
}
4) A provider defined through a string token. Although this is stated in the documentation, getting a provider through this method returns undefined values. This is a regression in Ivy which is enabled by default in Angular 9. A fix for this has been made but as of the publication of this article, it has not been included in any release. To get this to work, you’ll need to disable Ivy in the tsconfig.json file and use ViewEngine instead:
{
"angularCompilerOptions": {
"enableIvy": false,
}
}
Here’s how you can use a provider defined through a string token as a selector:
@Component({
selector: 'first-child',
providers: [{ provide: 'TokenA', useValue: 'ValueA' }]
})
export class FirstChildComponent{}
@Component({
selector: 'parent',
template: '<first-child></first-child>'
})
export class ParentComponent{
@ViewChild('TokenA') providerA: string;
}
However, if you’d like to use this type of selector with Ivy, you can use the read property to acquire a view query:
export class ParentComponent{
@ViewChild(FirstChildComponent, { read: 'TokenA' }) providerA: string;
}
5) A TemplateRef. It’s possible to access embedded templates using the @ViewChild decorator, which can then be used to instantiate embedded views with ViewContainerRef:
@Component({
selector: `container`,
template: `<ng-template><h1>This container is empty</h1></ng-template>`
})
export class ContainerComponent{
@ViewChild(TemplateRef) contTemplate: TemplateRef;
}
For a better understanding of how to use these view queries once configured, check out these live examples for each of these kinds of selectors. They illustrate how you can use view queries to access and modify embedded views.
The read property lets you select various tokens from the elements you query. These tokens could be provider tokens used for dependency injection or in some cases, be the type of view query. This is an optional property.
In the example below, the FirstChildComponent has a provider configuration with all kinds of dependency tokens like a class, string tokens, and an injection token. These tokens in conjunction with the read property can expose these dependencies to parent components that embed the FirstChildComponent. All these dependencies have been accessed in the ParentComponent using the ViewChild decorator and the read property specifying each of the corresponding tokens.
It’s also possible to specify the type the view query should be, using the read property. In the same example, the fcElementRef and fcComponent properties are both queries of FirstChildComponent but are of different types based on what the read property was specified as:
export class SampleService {}
export const ExampleServiceToken = new InjectionToken<string>('ExampleService');
@Component({
selector: 'first-child',
providers: [
SampleService,
{ provide: 'TokenA', useValue: 'valueA' },
{ provide: 'TokenB', useValue: 123 },
{ provide: ExampleServiceToken, useExisting: SampleService },
{ provide: 'TokenC', useValue: true }
]
})
export class FirstChildComponent{}
@Component({
selector: 'parent',
template: `<first-child></first-child>`
})
export class ParentComponent{
@ViewChild(FirstChildComponent, { read: 'TokenA' }) dependencyA: string;
@ViewChild(FirstChildComponent, { read: 'TokenB' }) dependencyB: number;
@ViewChild(FirstChildComponent, { read: 'TokenC' }) dependencyC: boolean;
@ViewChild(FirstChildComponent, { read: SampleService }) sampleService: SampleService;
@ViewChild(FirstChildComponent, { read: ElementRef }) fcElementRef: ElementRef;
@ViewChild(FirstChildComponent, { read: FirstChildComponent }) fcComponent: FirstChildComponent;
@ViewChild(FirstChildComponent, { read: ExampleServiceToken }) exampleService: SampleService;
}
The static property takes a boolean value and is optional. By default, it is false. If it is true, the view query is resolved before the complete competent view and data-bound properties are fully initialized. If set to false, the view query is resolved after the component view and data-bound properties are completely initialized.
In this example, the paragraph element is queried using both true and false static properties and the values logged for each in the ngOnInit and ngAfterViewInit callbacks:
@Component({
selector: 'display-name',
template: '<p #displayName>{{name}}</p>'
})
export class DisplayNameComponent implements OnInit, AfterViewInit{
@ViewChild('displayName', {static: true}) staticName: ElementRef;
@ViewChild('displayName', {static: false}) nonStaticName: ElementRef;
name: string = "Jane";
ngOnInit(){
logValues('OnInit');
}
ngAfterViewInit(){
logValues('AfterViewInit');
}
logValues(eventType: string){
console.log(`[${eventType}]\n staticName: ${this.staticName}, name value: "${this.staticName.nativeElement.innerHTML}"\n nonStaticName: ${this.nonStaticName}, name value: "${this.nonStaticName.nativeElement.innerHTML}"\n`);
}
}
This is what will be logged:
[OnInit] staticName: [object Object], name value: "" // static: true nonStaticName: undefined, name value: "" // static: false [AfterViewInit] staticName: [object Object], name value: "Jane" // static: true nonStaticName: [object Object], name value: "Jane" // static: false
In the ngOnInit callback, none of the interpolated values have been initialized but with { static: true}, the staticName view query is already resolved but the nonStaticName is undefined. However, after the AfterViewInit event, all the view queries have been resolved.
You can view these live examples that better illustrate how to use the read and static properties with the @ViewChild decorator.
The@ViewChildren decorator works similarly to the @ViewChild decorator but instead of configuring a single view query, it gets a query list. From the component view DOM, it retrieves a QueryList of child elements. This list is updated when any changes are made to the child elements. The @ViewChildren decorator takes two properties, a selector and a read property. These properties work in the same way as in the @ViewChild decorator. Any child elements that match will be part of the list. Here’s an example:
@Component({
selector: 'item-label',
template: `<h6>{{labelText}}</h6>`
})
export class ItemLabelComponent{
@Input() labelText: string;
}
@Component({
selector: 'item',
template: `<item-label *ngFor="let label of labels" [labelText]="label"></item-label>`
})
export class ItemComponent{
@ViewChildren(ItemLabelComponent) allLabels: ItemLabelComponent;
labels = ['recent', 'popular', 'new'];
}
The length of allLabels will be three as all the <item-label> will be selected. The QueryList has a number of methods you could use to manipulate the view queries.
For a more expansive illustration of how to use the @ViewChildren decorator and specify the read property, check out this example.
The @ViewChild and @ViewChildren decorators are excellent utilities for querying child elements in views. Understanding how to use them gives you more options for customizing component views. If you’d like to see more about how to use them, check out these examples.
Debugging Angular applications can be difficult, especially when users experience issues that are difficult to reproduce. If you’re interested in monitoring and tracking Angular state and actions for all of your users in production, try LogRocket.

LogRocket lets you replay user sessions, eliminating guesswork by showing exactly what users experienced. It captures console logs, errors, network requests, and pixel-perfect DOM recordings—compatible with all frameworks.
With Galileo AI, you can instantly identify and explain user struggles with automated monitoring of your entire product experience.
The LogRocket NgRx plugin logs Angular state and actions to the LogRocket console, giving you context around what led to an error, and what state the application was in when an issue occurred.
Modernize how you debug your Angular apps — start monitoring for free.

Vibe coding isn’t just AI-assisted chaos. Here’s how to avoid insecure, unreadable code and turn your “vibes” into real developer productivity.

GitHub SpecKit brings structure to AI-assisted coding with a spec-driven workflow. Learn how to build a consistent, React-based project guided by clear specs and plans.

:has(), with examplesThe CSS :has() pseudo-class is a powerful new feature that lets you style parents, siblings, and more – writing cleaner, more dynamic CSS with less JavaScript.

Kombai AI converts Figma designs into clean, responsive frontend code. It helps developers build production-ready UIs faster while keeping design accuracy and code quality intact.
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up now
One Reply to "Understanding the ViewChild and ViewChildren decorators in Angular 10"
In one word : Wow. This tutorial has
1) In-depth explanation of all the possibilities
2) Examples
I was writing notes as I read through the article. An explanation by a Pro