Skip to content

The Component Tree

Angular applications are built from components. Every component is responsible for one piece of the UI. Together, they form a tree — a hierarchy where components contain other components, all the way down from one root at the top.

When bootstrapApplication runs, it renders the root component — App — into the <app-root> element in index.html. From there, App’s template can include other components, which can include others, and so on.

App (root)
├── NavBar
│ └── SearchForm
├── RouterOutlet
│ ├── Home
│ │ └── MovieCard (×n)
│ ├── Browse
│ │ └── MovieCard (×n)
│ ├── MovieDetail
│ └── Watchlist
│ └── MovieCard (×n)
└── Toast

This is the CinemaVault component tree. Every box is a component — a TypeScript class with its own template, styles, and logic.

A component includes another component by adding its selector to its template. Here is a simplified App template that includes a NavBar component:

app.html
<app-nav-bar />
<main>
<router-outlet />
</main>
<app-toast />

Angular sees <app-nav-bar /> and looks for a component whose selector is 'app-nav-bar'. It renders that component in place.

The <router-outlet /> is a special Angular component that renders whichever page component matches the current URL.

When component A includes component B in its template, A is the parent and B is the child. This relationship determines how data flows:

  • Data flows down: parents pass data to children via @Input() properties
  • Events flow up: children emit events that parents listen to via @Output() properties

In CinemaVault, Home passes individual Movie objects down to MovieCard. MovieCard emits an event when the user clicks the watchlist toggle button. Home listens for that event and calls the WatchlistService.

The tree gives Angular a clear mental model for:

  1. Rendering: Angular renders from the root down. When data changes, it re-renders only the affected subtrees.
  2. Dependency injection: Services provided at the root are available to any component in the tree.
  3. Communication: Data flows down via inputs; events flow up via outputs. This predictable flow makes large apps understandable.

Look at the CinemaVault repository and notice how the src/app/ directory maps to the tree:

src/app/
├── app.ts ← root (App)
├── components/
│ ├── nav-bar/ ← NavBar (always visible)
│ ├── movie-card/ ← MovieCard (used on 3 pages)
│ └── toast/ ← Toast (always visible)
└── pages/
├── home/ ← Home (route: /)
├── browse/ ← Browse (route: /browse)
├── search-results/ ← SearchResults (route: /search)
├── movie-detail/ ← MovieDetail (route: /movies/:id)
└── watchlist/ ← Watchlist (route: /watchlist)

Shared components that appear on multiple pages live in components/. Page-level components that correspond to routes live in pages/.

  1. On paper or in a drawing tool, sketch the component tree for a hypothetical blog app. It should have: a Header, a PostList (on the main page), a PostCard (inside PostList), a Sidebar, and a single PostDetail page.
  2. Look at the CinemaVault source. Find the app.html file. Which components does it include directly?
  3. In the tree diagram at the top of this lesson, MovieCard appears three times (under Home, Browse, and Watchlist). Why is this fine?
  • Every Angular app is a tree of components rooted at App.
  • Components nest by including other components’ selectors in their templates.
  • <router-outlet> renders whichever page component matches the current URL.
  • Data flows down via @Input(); events flow up via @Output().
  • Shared components live in components/; page components live in pages/ by convention.