Draft of the Revised Angular Style Guide

In 2016, alongside Angular 2.0.0, a comprehensive 52-page coding style guide was introduced. Over the past eight years and 16 subsequent versions, the Angular framework has evolved significantly. Recognizing the need for updated guidance, Jeremy Elbourn, Angular’s technical lead at Google, has initiated a substantial revision of the official style guide.

Draft of the new Angular coding style guide.

Primary goals of the Angular team

Jeremy outlines the Angular team’s goals for the new style guide in this RFC on the Angular GitHub repo:

  • Prioritize style choices over general best practices.
  • Modernize guidance to reflect new features and APIs.
  • Update recommendations based on real world observations.
  • Condense the guide to 4 pages (down from 52), simplifying it significantly.
  • Remove non-Angular guidance instead linking to Google's TS style guide.

Well it's a draft, why should I care?

Although the new style guide is still a draft and may take some time to be officially released (v20.0.0 would be fitting after v2.0.0), I believe we should start applying it today.

Overall, I find the key points in the new style guide both valid and beneficial. This post aims to highlight some of the most noteworthy aspects.

General thoughts

In the introduction Jeremy writes:

When in doubt, prefer consistency

I completely agree! Even though these rules aren’t part of the official style guide, I always emphasize my three favorite frontend development rules in Angular essential and other workshops:

  • Keep it short & simple (prefer less code, limit files to max. 400 LoC, prefer small functions, ...)
  • Don't repeat yourself (create helpers, services, pipes, ...)
  • Be consistent (use Prettier, adhere to style guide(s), ...)

Small is beautiful (added by me)

Though the 400 LoC limit is being removed from the new "Angular-specific" style guide, I believe it remains a valuable best practice. In my experience with numerous Angular projects, many components exceed this limit, often leading to complexities that make maintenance challenging for developers. Keeping components within a manageable size can significantly ease long-term upkeep and thus improve developers lives. There are many ways to reduce the complexity of components, I'll just mention three important ones:

  • Create Angular building blocks like subcomponents, directives, services, pipes
  • Use state management or component state facades (services)
  • Delegate helper functions into separate files / classes

Jeremy also highlights updates to file naming conventions and project structure recommendations in the new style guide. These changes aim to bring clarity and consistency, making it easier for developers to navigate and manage Angular projects effectively.

Naming of files

Okay, the file naming conventions are set to change, but I won’t dive into specifics here since they may still be adjusted. I anticipate a migration script will be provided to handle renaming, making the transition seamless.

Project structure

One key point in the structure recommendations is to group features into folders, aligning well with our Angular Architects Team’s approach to structuring enterprise Angular apps for a clean, maintainable codebase:

  • We can use an Nrwl Nx monorepo with libraries to organize features, or
  • use the lightweight tool Sheriff to enforce feature boundaries.

In both cases, we suggest (though it’s optional) applying domain-driven design (DDD) to define feature boundaries. You can explore this further in Manfred’s post on Strategic Design with Sheriff and Standalone Components.

Another valuable guideline is: One concept per file. Keeping files focused on a single concept — Angular building blocks, types, etc. — helps maintain clarity and simplicity.

Highlights of the new style guide

Here are a few personal highlights I’d like to point out, along with some minor adjustments and remarks:

Keep components focused on presentation

Avoid complex business logic in components. Delegate this logic to your store or services. Additionally, if template code becomes overly complex, refactor that logic into the TypeScript code to improve readability and maintainability.

Group Angular-specific properties before methods

This approach prioritizes organizing inputs, outputs, and queries first, followed by other properties, and then methods. Personally, I also prefer grouping all injected dependencies below, sorted alphabetically, before the first method. As Jeremy notes, “This practice makes it easier to find the class’s template APIs and dependencies.”

Keep (constructor and) lifecycle methods simple

Avoid placing lengthy or complex logic directly in the constructor or lifecycle hooks like ngOnInit. Instead, create well-named methods to house that logic and simply call those methods. This approach enhances readability, making it easier to understand a component’s functionality at a glance.

ngOnInit(): void { // <-- don't forget to add the return type on all your methods ;-)
    this.startLogging();
    this.runBackgroundTask(); // <-- not sure if this is the best possible method name ;-)
}

Use protected on component class members used in the template

Applying access modifiers to limit access to a class’s fields is always a good practice for enhancing code quality. When I see code without them, it immediately feels sloppy.

A month ago, after a poll within the Angular Architects Team, we concluded that using protected for fields accessed in a component’s template is a good practice. It’s great to see this now reflected in the official style guide! A small addition: if a field isn’t used in the template, the default should, of course, be private.

Small note: Personally, I strongly discourage typing the public modifier, since it’s the default and doesn’t add any value. Of course for our fields (members and methods) in the Angular building blocks public (by not adding a modifier 😏) is rather an exception than a default.

@Component({
    /* ... */
    template: `<p>{{ fullName() }}</p>`,
})
export class UserProfile {
    readonly firstName = input();
    readonly lastName = input();

    // `fullName` is not part of the component's API, but is used in the template
    protected readonly fullName = computed(() => `${this.firstName()} ${this.lastName()}`);
}

Use readonly on properties initialized by Angular (and more)

More than a year ago, I started adding the readonly modifier to almost everything—much like preferring const over let. This includes Angular signals, dependency injection fields, Output, and query APIs. Not for Input properties, though, since readonly wouldn’t work there. It’s a bit of extra work, but I think it’s worth the effort for the added clarity and structure.

@Component({
    /* ... */
})
export class UserProfile {
    readonly userId = input();
    readonly userSaved = output();

    private readonly userService = inject(UserService);
}

Prefer class and style over ngClass and ngStyle

I’ve been teaching this approach for years in my workshops. It makes code easier to read and understand, and it aligns nicely with tools like Prettier.

<div [class.admin]="isAdmin" [class.dense]="density === 'high'"></div>

Name event handlers for what they do, not for the triggering event

I’ve recently started adopting this approach, as it helps clarify what an event does just by reading the template. Overall, using clear and meaningful names for symbols and methods is crucial for readability and maintainability.

<button (click)="saveUserData()">Save</button>

Workshops

If you want to deep dive into Angular, we offer a variety of workshops - both in English and German.

Also, if you wanna deep dive into quality, make sure to check out the: