Angular Basics #2: Components and Template Syntax
Last time, we looked at what Angular is and what its strengths are. From this post on, you start writing actual code. It’s not an exaggeration to say that learning Angular starts with the Component and ends with the component — components are the basic unit of every screen.
There are four things to do in this post.
- Install Node.js and Angular CLI
- Create your first project with
ng new - Understand the structure of a single component (
@Componentdecorator) - Create a new component and slot it into a parent component
Installing Node.js and Angular CLI #
To develop with Angular, you first need Node.js. The Angular CLI itself runs on Node.js, and the build/test tools all use the Node environment.
Visit nodejs.org and install the LTS (Long Term Support) version. At the time of writing, the LTS is the Node 22 line. On Mac, you can also install via Homebrew.
brew install nodeOnce installation is done, open a new terminal and check the versions.
node -v
npm -vIf Node and npm versions print out, you’re good. Now install Angular CLI, the standard Angular tool, globally.
npm install -g @angular/cli-g is short for “global.” It installs the package system-wide so you can use the ng command from any folder. After installation, verify with:
ng versionIf you see the Angular CLI version along with an ASCII-art Angular logo, you’re set. This series targets Angular v17 or later (the point where Standalone Components are the default).
ng version, your npm global path config may have an issue. In most cases, installing Node via nvm or Homebrew solves it.Creating your first project #
Move to the location you want (e.g., ~/projects or Desktop) and run:
ng new my-appmy-app is the project folder name — feel free to use a different one. When you run the command, you’ll get a couple of questions.
- Which stylesheet format would you like to use? — picks the style format. Choose
CSS(the most neutral choice for beginners; pick SCSS, Sass, or Less if you’re already comfortable with them). - Do you want to enable Server-Side Rendering (SSR) and Static Site Generation (SSG/Prerendering)? — asks whether to enable SSR/SSG. Answer
Nofor the basics. You can add it as an option later when you need it.
Once the questions are done, Angular CLI creates the folder and installs dependencies automatically. It can take a while, so feel free to grab a tea.
Once installation is done, take a look at the folder structure.
my-app/
├── node_modules/ ← installed libraries
├── public/ ← static files (favicon, etc.)
├── src/ ← the code we'll write
│ ├── app/
│ │ ├── app.component.ts ← root component (TS)
│ │ ├── app.component.html ← root component (template)
│ │ ├── app.component.css ← root component (styles)
│ │ ├── app.config.ts ← app config (routing, providers, etc.)
│ │ └── app.routes.ts ← routing definitions
│ ├── index.html ← HTML where the app is injected
│ ├── main.ts ← app entry point (bootstrap)
│ └── styles.css ← global styles
├── angular.json ← Angular CLI config
├── package.json ← project info and dependencies
└── tsconfig.json ← TypeScript configThe most important folder at this stage is src/app/. Every component you’ll create goes inside it.
Running the dev server #
Now move into the project folder and start the dev server.
cd my-app
ng serveIf you see something like the following, it worked.
➜ Local: http://localhost:4200/
➜ press h + enter to show helpOpen your browser at http://localhost:4200. If you see a welcome screen with the Angular logo, everything is fine.
In that state, change a bit of text in src/app/app.component.html and save. The browser updates immediately without a refresh. That’s HMR (Hot Module Replacement) — a dev feature that redraws only the changed part in real time.
Ctrl + C in the terminal. To start again, run ng serve from the same folder. To change the port, pass an option like ng serve --port 4300.The shape of a single component #
Now to the real point. An Angular component usually moves as a set of three files.
app.component.ts— the component’s class (TypeScript)app.component.html— the template that draws the screenapp.component.css— styles applied only to this component
Open src/app/app.component.ts and you’ll see something like this.
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet],
templateUrl: './app.component.html',
styleUrl: './app.component.css',
})
export class AppComponent {
title = 'my-app';
}It looks foreign at first, but break it down line by line and it’s surprisingly simple.
@Component({...})— a decorator that declares “make this class an Angular component.” It attaches metadata to theAppComponentclass below it.selector: 'app-root'— the tag name to use when you reference this component in HTML. You’ll use it as<app-root></app-root>.standalone: true— means this component is a Standalone Component. In the past, components had to be bundled into an NgModule, but in modern Angular components run independently without a module.imports: [...]— where you pre-register other components or directives this component’s template will use. The example registersRouterOutlet, used for routing.templateUrl/styleUrl— paths to the template and style files. For a short component, you can also write them inline astemplate: '<h1>...</h1>'instead of separate files.export class AppComponent— the actual component body. Where data (class fields) and behavior (methods) live.
A simple analogy: @Component is “a label that describes what kind of screen piece this class is,” and the class below it is “the brain of that piece.”
Interpolation #
To display data defined on the class in the template, you use interpolation. Notice the field title = 'my-app' we created above. Let’s display its value on the screen.
Open src/app/app.component.html, clear all the contents, and write:
<h1>Hello, {{ title }}!</h1>
<p>This is my first Angular app.</p>When you save, the browser shows “Hello, my-app!”. When you write a class property inside double curly braces ({{ }}), its value gets printed on the screen. That’s interpolation.
Curly braces can hold not just simple properties but simple expressions too.
<h1>Hello, {{ title.toUpperCase() }}!</h1>
<p>1 + 2 = {{ 1 + 2 }}</p>That said, don’t put overly complex logic inside template expressions. For maintainability, push complex calculations into class methods or getters and call only the result in the template.
Creating a new component #
You can’t build a whole app with just the root component (AppComponent). The basic mindset of Angular (and every component-based framework) is to break the screen into small pieces, make each piece a separate component, and assemble them.
You create new components with Angular CLI.
ng generate component user-cardIf typing the long form is annoying, there’s a short form too.
ng g c user-cardRunning the command generates these files automatically inside src/app/user-card/.
src/app/user-card/
├── user-card.component.ts
├── user-card.component.html
├── user-card.component.css
└── user-card.component.spec.ts ← test fileOpen user-card.component.ts and you’ll see code that looks almost the same as the AppComponent we saw earlier.
import { Component } from '@angular/core';
@Component({
selector: 'app-user-card',
standalone: true,
imports: [],
templateUrl: './user-card.component.html',
styleUrl: './user-card.component.css',
})
export class UserCardComponent {
name = 'Curtis';
role = 'Frontend Developer';
}I added name and role fields myself. Now write the template.
<div class="card">
<h2>{{ name }}</h2>
<p>{{ role }}</p>
</div>Add a touch of style too.
.card {
border: 1px solid #ddd;
border-radius: 8px;
padding: 16px;
width: 240px;
}This component’s selector is app-user-card. So if you put <app-user-card></app-user-card> somewhere in HTML, this component is drawn there.
Assembling components #
Now let’s slot the UserCardComponent we built into the root component, AppComponent. Two steps are needed.
First, register the child component in the parent’s imports array. Standalone components don’t have an NgModule, so you must explicitly import the components you’ll use.
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { UserCardComponent } from './user-card/user-card.component';
@Component({
selector: 'app-root',
standalone: true,
imports: [RouterOutlet, UserCardComponent],
templateUrl: './app.component.html',
styleUrl: './app.component.css',
})
export class AppComponent {
title = 'my-app';
}Then use the child’s selector in the parent template.
<h1>Hello, {{ title }}!</h1>
<app-user-card></app-user-card>
<app-user-card></app-user-card>Save, and you’ll see two UserCard cards drawn on the screen. Like Lego blocks, components can be slotted into other components’ templates and reused multiple times in different places.
imports every time?” Standalone components don’t have a giant registry like NgModule, so each component explicitly brings in only what it needs. It feels tedious at first, but per-component dependencies become clear, with big benefits for tree-shaking and bundle optimization.Of course, the two cards currently show the same data, which is a limitation. To show a different person’s information per card, the parent needs to pass data to the children — and that’s the topic of the next post.
Recap #
In this post, we installed Node.js and Angular CLI, created our first project with ng new, and looked at the structure of the @Component decorator. We also displayed class data on the screen with interpolation ({{ }}) and used ng generate component to create a new component and slot it into a parent template.
Even with just this much, you should have a big-picture view of how an Angular app is assembled component by component. In the next post, “Angular Basics #3: Data Binding and Events,” you’ll dig into property binding ([name]="...") for passing data from parent to child, and event binding ((click)="...") for handling events like user clicks.