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.
- Best Practices Workshop, Nov. 18th to 20th 📈
- Accessibility Workshop, Dec. 12th to 13th ♿
- Performance Workshop, Dec. 16th to 18th 🚀
Also, if you wanna deep dive into quality, make sure to check out the:
- Angular Quality Workshop, Nov. 28th by my colleague Rainer Hahnekamp.