> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/angular/angular/llms.txt
> Use this file to discover all available pages before exploring further.

# Angular Style Guide

> Comprehensive style guide for Angular applications covering naming conventions, project structure, and coding best practices

# Angular Style Guide

This guide covers a range of style conventions for Angular application code. These recommendations are not required for Angular to work, but instead establish a set of coding practices that promote consistency across the Angular ecosystem.

## Naming Conventions

### File Naming

<CardGroup cols={2}>
  <Card title="Use Hyphens" icon="minus">
    Separate words within a file name with hyphens (`-`). For example, a component named `UserProfile` has a file name `user-profile.ts`.
  </Card>

  <Card title="Match Identifiers" icon="code">
    File names should generally describe the contents of the code in the file. When the file contains a TypeScript class, the file name should reflect that class name.
  </Card>
</CardGroup>

<CodeGroup>
  ```typescript user-profile.component.ts theme={null}
  import { Component } from '@angular/core';

  @Component({
    selector: 'app-user-profile',
    templateUrl: './user-profile.component.html',
    styleUrl: './user-profile.component.css'
  })
  export class UserProfileComponent {
    // Component logic
  }
  ```

  ```typescript user-profile.component.spec.ts theme={null}
  import { ComponentFixture, TestBed } from '@angular/core/testing';
  import { UserProfileComponent } from './user-profile.component';

  describe('UserProfileComponent', () => {
    let component: UserProfileComponent;
    let fixture: ComponentFixture<UserProfileComponent>;

    beforeEach(async () => {
      await TestBed.configureTestingModule({
        imports: [UserProfileComponent]
      }).compileComponents();
    });
  });
  ```
</CodeGroup>

### Component Files Structure

Components typically consist of one TypeScript file, one template file, and one style file. These files should share the same name with different file extensions:

```
user-profile/
├── user-profile.component.ts
├── user-profile.component.html
├── user-profile.component.css
└── user-profile.component.spec.ts
```

<Note>
  For unit tests, end file names with `.spec.ts`. For example, the unit test file for the `UserProfile` component has the file name `user-profile.spec.ts`.
</Note>

## Project Structure

### Source Directory Organization

All of your Angular UI code (TypeScript, HTML, and styles) should live inside a directory named `src`. Code that's not related to UI, such as configuration files or scripts, should live outside the `src` directory.

```
my-angular-app/
├── src/
│   ├── app/
│   │   ├── features/
│   │   ├── shared/
│   │   └── main.ts
│   ├── assets/
│   └── index.html
├── angular.json
├── package.json
└── tsconfig.json
```

### Feature-Based Organization

Organize your project into subdirectories based on the features of your application or common themes to the code in those directories:

<Tabs>
  <Tab title="Good Structure">
    ```
    src/app/
    ├── movie-reel/
    │   ├── show-times/
    │   │   ├── film-calendar/
    │   │   └── film-details/
    │   └── reserve-tickets/
    │       ├── payment-info/
    │       └── purchase-confirmation/
    └── user/
        ├── profile/
        └── settings/
    ```
  </Tab>

  <Tab title="Avoid This">
    ```
    src/app/
    ├── components/
    │   ├── film-calendar/
    │   ├── payment-info/
    │   └── user-profile/
    ├── services/
    │   ├── movie.service.ts
    │   └── user.service.ts
    └── directives/
    ```
  </Tab>
</Tabs>

<Warning>
  Avoid creating subdirectories based on the type of code that lives in those directories. For example, avoid creating directories like `components`, `directives`, and `services`.
</Warning>

### Bootstrap in main.ts

The code to start up, or **bootstrap**, an Angular application should always live in a file named `main.ts`. This represents the primary entry point to the application.

```typescript main.ts theme={null}
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { appConfig } from './app/app.config';

bootstrapApplication(AppComponent, appConfig)
  .catch((err) => console.error(err));
```

## Dependency Injection

### Prefer inject() Function

Prefer using the `inject()` function over injecting constructor parameters. The `inject()` function offers several style advantages:

<CardGroup cols={2}>
  <Card title="Better Readability" icon="eye">
    More readable, especially when a class injects many dependencies
  </Card>

  <Card title="Better Type Inference" icon="wand-magic-sparkles">
    Offers better type inference and easier to add comments
  </Card>
</CardGroup>

<CodeGroup>
  ```typescript Modern Approach (Preferred) theme={null}
  import { Component, inject } from '@angular/core';
  import { UserService } from './user.service';
  import { LoggerService } from './logger.service';

  @Component({
    selector: 'app-user-dashboard',
    template: `<div>{{ userName() }}</div>`
  })
  export class UserDashboardComponent {
    // Cleaner and more readable
    private userService = inject(UserService);
    private logger = inject(LoggerService);
    
    userName = computed(() => this.userService.getCurrentUser().name);
  }
  ```

  ```typescript Legacy Approach (Avoid) theme={null}
  import { Component } from '@angular/core';
  import { UserService } from './user.service';
  import { LoggerService } from './logger.service';

  @Component({
    selector: 'app-user-dashboard',
    template: `<div>{{ userName() }}</div>`
  })
  export class UserDashboardComponent {
    constructor(
      private userService: UserService,
      private logger: LoggerService
    ) {}
    
    userName = computed(() => this.userService.getCurrentUser().name);
  }
  ```
</CodeGroup>

## Components and Directives

### Component Selectors

Always use an application-specific prefix for component selectors to avoid naming conflicts with third-party components:

```typescript theme={null}
@Component({
  selector: 'app-user-profile',  // ✅ Good: uses 'app' prefix
  // ...
})
export class UserProfileComponent {}

@Component({
  selector: 'user-profile',  // ❌ Avoid: no prefix
  // ...
})
export class UserProfileComponent {}
```

### Member Access Modifiers

Use `protected` on class members that are only used by a component's template:

```typescript theme={null}
import { Component, computed, input } from '@angular/core';

@Component({
  selector: 'app-user-profile',
  template: `<p>{{ fullName() }}</p>`
})
export class UserProfile {
  firstName = input<string>();
  lastName = input<string>();

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

### Use readonly for Angular Properties

Mark component and directive properties initialized by Angular as `readonly`. This includes properties initialized by `input`, `model`, `output`, and queries:

```typescript theme={null}
import { Component, input, output, model, viewChild } from '@angular/core';

@Component({
  selector: 'app-user-form',
  template: `...`
})
export class UserFormComponent {
  readonly userId = input<string>();
  readonly userSaved = output<void>();
  readonly userName = model<string>();
  readonly submitButton = viewChild<ElementRef>('submit');
}
```

### Organize Class Members

Group Angular-specific properties together, typically near the top of the class declaration:

```typescript theme={null}
import { Component, inject, input, output, viewChild } from '@angular/core';
import { UserService } from './user.service';

@Component({
  selector: 'app-user-detail',
  template: `...`
})
export class UserDetailComponent {
  // 1. Injected dependencies
  private userService = inject(UserService);
  
  // 2. Inputs
  readonly userId = input.required<string>();
  readonly editable = input(false);
  
  // 3. Outputs
  readonly userUpdated = output<User>();
  
  // 4. Queries
  readonly nameInput = viewChild<ElementRef>('name');
  
  // 5. Other properties
  protected isLoading = signal(false);
  
  // 6. Methods
  saveUser() {
    // Implementation
  }
}
```

## Template Best Practices

### Prefer class and style Bindings

Prefer `class` and `style` bindings over using the `NgClass` and `NgStyle` directives:

<CodeGroup>
  ```html Preferred Approach theme={null}
  <div 
    [class.admin]="isAdmin" 
    [class.dense]="density === 'high'"
    [style.color]="textColor"
    [style.background-color]="backgroundColor">
    Content
  </div>

  <!-- OR with object syntax -->
  <div 
    [class]="{admin: isAdmin, dense: density === 'high'}"
    [style]="{'color': textColor, 'background-color': backgroundColor}">
    Content
  </div>
  ```

  ```html Avoid This theme={null}
  <div 
    [ngClass]="{admin: isAdmin, dense: density === 'high'}"
    [ngStyle]="{'color': textColor, 'background-color': backgroundColor}">
    Content
  </div>
  ```
</CodeGroup>

<Info>
  Both `class` and `style` bindings use a more straightforward syntax that aligns closely with standard HTML attributes. Additionally, they incur less performance overhead compared to the `NgClass` and `NgStyle` directives.
</Info>

### Name Event Handlers Meaningfully

Prefer naming event handlers for the action they perform rather than for the triggering event:

<CodeGroup>
  ```html Good Example theme={null}
  <button (click)="saveUserData()">Save</button>
  <button (click)="deleteUser()">Delete</button>
  <textarea (keydown.control.enter)="commitNotes()"></textarea>
  ```

  ```html Avoid This theme={null}
  <button (click)="handleClick()">Save</button>
  <button (click)="onClick()">Delete</button>
  <textarea (keydown)="handleKeydown($event)"></textarea>
  ```
</CodeGroup>

### Keep Lifecycle Methods Simple

Avoid putting long or complex logic inside lifecycle hooks. Instead, create well-named methods to contain that logic:

<CodeGroup>
  ```typescript Preferred theme={null}
  export class AppComponent implements OnInit {
    ngOnInit() {
      this.startLogging();
      this.runBackgroundTask();
      this.loadUserPreferences();
    }
    
    private startLogging() {
      this.logger.setMode('info');
      this.logger.monitorErrors();
    }
    
    private runBackgroundTask() {
      // Complex logic here
    }
  }
  ```

  ```typescript Avoid theme={null}
  export class AppComponent implements OnInit {
    ngOnInit() {
      // All logic inline - hard to understand
      this.logger.setMode('info');
      this.logger.monitorErrors();
      this.backgroundService.schedule({
        interval: 5000,
        callback: () => {
          // More complex logic...
        }
      });
    }
  }
  ```
</CodeGroup>

### Avoid Complex Template Logic

When the code in a template gets too complex, refactor logic into the TypeScript code, typically with a computed signal:

<CodeGroup>
  ```typescript Good Example theme={null}
  @Component({
    selector: 'app-product-list',
    template: `
      @for (product of filteredProducts(); track product.id) {
        <div>{{ product.name }} - {{ displayPrice(product) }}</div>
      }
    `
  })
  export class ProductListComponent {
    products = signal<Product[]>([]);
    searchTerm = signal('');
    
    // Complex logic in TypeScript
    protected filteredProducts = computed(() => {
      const term = this.searchTerm().toLowerCase();
      return this.products().filter(p => 
        p.name.toLowerCase().includes(term) ||
        p.category.toLowerCase().includes(term)
      );
    });
    
    protected displayPrice(product: Product): string {
      return `$${product.price.toFixed(2)}`;
    }
  }
  ```

  ```typescript Avoid theme={null}
  @Component({
    selector: 'app-product-list',
    template: `
      @for (product of products().filter(p => 
        p.name.toLowerCase().includes(searchTerm().toLowerCase()) ||
        p.category.toLowerCase().includes(searchTerm().toLowerCase())
      ); track product.id) {
        <div>{{ product.name }} - ${{ product.price.toFixed(2) }}</div>
      }
    `
  })
  export class ProductListComponent {
    products = signal<Product[]>([]);
    searchTerm = signal('');
  }
  ```
</CodeGroup>

## TypeScript Best Practices

### Use Lifecycle Hook Interfaces

When adding a lifecycle hook to your class, import and `implement` these interfaces to ensure that the methods are named correctly:

```typescript theme={null}
import { Component, OnInit, OnDestroy } from '@angular/core';

@Component({
  selector: 'app-user-list',
  template: `...`
})
export class UserListComponent implements OnInit, OnDestroy {
  ngOnInit() {
    // The OnInit interface ensures this method is named correctly
  }
  
  ngOnDestroy() {
    // The OnDestroy interface ensures this method is named correctly
  }
}
```

### Prefer const over let

Use `const` wherever possible, only using `let` when a value must change. Avoid `var` unless absolutely necessary:

```typescript theme={null}
// ✅ Good
const maxUsers = 100;
const apiUrl = 'https://api.example.com';
let currentPage = 1;  // Use let when value changes

// ❌ Avoid
var maxUsers = 100;  // Don't use var
let apiUrl = 'https://api.example.com';  // Use const for constants
```

### Avoid any Type

Avoid `any` where possible. Consider whether a generic or `unknown` may be appropriate:

<CodeGroup>
  ```typescript Good Example theme={null}
  function processData<T>(data: T): T {
    return data;
  }

  function handleError(error: unknown) {
    if (error instanceof Error) {
      console.error(error.message);
    }
  }
  ```

  ```typescript Avoid theme={null}
  function processData(data: any): any {
    return data;
  }

  function handleError(error: any) {
    console.error(error.message);
  }
  ```
</CodeGroup>

## Summary

<AccordionGroup>
  <Accordion title="Key Naming Rules">
    * Use hyphen-case for file names (e.g., `user-profile.component.ts`)
    * Use application-specific prefixes for selectors (e.g., `app-user-profile`)
    * Use PascalCase for class names
    * Use camelCase for functions and methods
    * Use UPPER\_SNAKE\_CASE for constants
  </Accordion>

  <Accordion title="Project Organization">
    * Organize by feature, not by type
    * Keep related files together in the same directory
    * Bootstrap in `main.ts` directly inside `src`
    * One concept per file
  </Accordion>

  <Accordion title="Component Best Practices">
    * Use `inject()` function over constructor injection
    * Use `protected` for template-only members
    * Use `readonly` for Angular-initialized properties
    * Group Angular properties before methods
    * Keep lifecycle methods simple
  </Accordion>

  <Accordion title="Template Best Practices">
    * Prefer `class` and `style` bindings over NgClass/NgStyle
    * Name event handlers for what they do
    * Avoid complex template logic
    * Refactor complex expressions to computed signals
  </Accordion>
</AccordionGroup>

<Card title="Next Steps" icon="arrow-right" href="/best-practices/performance">
  Learn about performance optimization techniques in Angular
</Card>
