These coding standards ensure consistency throughout the Angular Material codebase and help maintain high code quality.
General Principles
Write Useful Comments Explain why , not just what
Prefer Focused Components Small, granular components over complex, configurable ones
Small Modules Keep files under 400 lines when possible
Less is More Avoid adding features that don’t offer high value
/**
* JsDoc-style comments for descriptions
* Used on classes, methods, properties
*/
class MyComponent {
/** The current theme color. */
color : string ;
// Regular comments for explanations
// Use for background info and context
}
Component Design
Prefer Focused Components
< mat-button > Basic button </ mat-button >
< mat-button class = "mat-fab" > FAB </ mat-button >
< mat-button class = "mat-icon-button" > icon </ mat-button >
❌ Using classes to drastically change behavior < mat-button > Basic button </ mat-button >
< mat-fab > FAB </ mat-fab >
< mat-icon-button > icon </ mat-icon-button >
✅ Separate components for distinct behaviors
Module Organization
Keep modules focused
Single responsibility principle - one module, one purpose
Ideal file size
Target 200-300 lines per file
Refactor threshold
Start refactoring around 400 lines (excluding long constants/comments)
Code Style
Column Limit
All code and docs must be 100 columns or fewer .
This applies to:
TypeScript
SCSS
HTML
Bash scripts
Markdown files
API Design
Avoid Boolean Arguments
function getTargetElement ( createIfNotFound = false ) {
// "Do something extra" parameter
}
❌ Boolean arguments that mean “do something extra” are unclear. function getExistingTargetElement () {
// ...
}
function createTargetElement () {
// ...
}
✅ Separate functions with clear intent.
TypeScript
Typing
// ❌ Bad
function process ( data : any ) {
// ...
}
// ✅ Good
function process < T >( data : T ) {
// ...
}
// ✅ Also good
function process ( data : unknown ) {
if ( typeof data === 'string' ) {
// Type narrowing
}
}
Explicit types for public API
export class MyComponent {
// ✅ Explicit return type
getValue () : string {
return this . _value ;
}
// ✅ Explicit parameter types
setValue ( value : string ) : void {
this . _value = value ;
}
private _value : string = '' ;
}
Documentation tooling requires explicit types for public APIs.
Fluent APIs
class ConfigBuilder {
// Use 'this' return type for chaining
withName ( name : string ) : this {
this . config . name = name ;
return this ;
}
withColor ( color : string ) : this {
this . config . color = color ;
return this ;
}
}
// Usage:
const config = new ConfigBuilder ()
. withName ( 'my-component' )
. withColor ( 'primary' );
Access Modifiers
Omit the public keyword - it’s the default
Use private with underscore prefix for truly private members
Use protected when appropriate, no prefix
Prefix library-internal properties with underscore without private keyword
export class MyComponent {
// ✅ Public - no keyword
value : string ;
// ✅ Private - keyword + prefix
private _state : State ;
// ✅ Protected - keyword only
protected config : Config ;
// ✅ Internal - prefix only (used in templates)
_elementRef : ElementRef ;
}
Use @docs-private JSDoc annotation to hide symbols from public API docs.
Getters and Setters
Use for @Input properties
@ Input ()
get disabled (): boolean {
return this . _disabled ;
}
set disabled ( value : BooleanInput ) {
this . _disabled = coerceBooleanProperty ( value );
}
private _disabled = false ;
Keep them simple
If logic takes more than 3 lines, extract to a method.
Getter before setter
Always place getter immediately before its setter.
Decorate getters only
@ Input () // ✅ On getter
get value (): string {
return this . _value ;
}
set value ( v : string ) { // No decorator
this . _value = v ;
}
Prefer readonly properties
// ✅ Prefer this
readonly active : boolean ;
// ❌ Over this
get active (): boolean {
return this . _active ;
}
Properties
Methods
Boolean Properties
/** The label position relative to the checkbox. Defaults to 'after'. */
@ Input () labelPosition : 'before' | 'after' = 'after' ;
/**
* Opens a modal dialog containing the given component.
* @param component Type of the component to load into the dialog.
* @param config Dialog configuration options.
* @returns Reference to the newly-opened dialog.
*/
open < T >( component : ComponentType < T > , config ?: MatDialogConfig ): MatDialogRef < T > {
// ...
}
/** Whether the button is disabled. */
disabled : boolean = false ;
Use “Whether…” not “True if…”
Naming
Write out words instead of abbreviations
Prefer exact names: labelPosition over align
Use is and has prefixes for booleans (except @Input properties)
Don’t suffix observables with $
// ❌ Bad - describes usage
class RadioService { }
// ✅ Good - describes purpose
class UniqueSelectionDispatcher { }
Name based on responsibility
Avoid “Service” suffix
Think of it as a job title
Prefix directives: Mat for Material, Cdk for CDK
// ❌ Bad - describes when it's called
handleClick () {
// ...
}
// ✅ Good - describes what it does
activateRipple () {
// ...
}
Capture the action performed, not when it’s called.
Components:
Lowercase with hyphens: mat-button
Use element selectors (exceptions for native elements)
Directives:
camelCase: matTooltip
Exceptions for components with empty templates
Patterns to Avoid
Don’t Use Inheritance for Behavior
// ❌ Limits composition
class MyButton extends BaseButton {
// Can only inherit from one class
}
// ✅ Allows multiple behaviors
class MyButton extends mixinDisabled ( mixinColor ( BaseClass )) {
// Can mix in multiple behaviors
}
Use TypeScript mixins instead.
import { Input , booleanAttribute , numberAttribute } from '@angular/core' ;
@ Input ({ transform: booleanAttribute }) disabled : boolean = false ;
@ Input ({ transform: numberAttribute }) tabIndex : number = 0 ;
This allows:
< component disabled ></ component >
< component tabIndex = "5" ></ component >
CSS / SCSS
Be Cautious with Flexbox
Flex baseline calculation differs from other display values
Difficult to align flex elements with standard elements
Never use flex on elements with projected content
Component outermost elements should be block or inline-block
Specificity
.mat-calendar {
display : block ;
.mat-month {
display : inline-block ;
.mat-date.mat-selected {
font-weight : bold ;
}
}
}
❌ Nested selectors increase specificity .mat-calendar {
display : block ;
}
.mat-calendar-month {
display : inline-block ;
}
.mat-calendar-date.mat-selected {
font-weight : bold ;
}
✅ Flat selectors, easy to override
Best Practices
Never set margin on host
Let users control component spacing.
Style host when possible
// ✅ Prefer
the-host-element {
color : red ;
}
// ❌ Over
the-host-element {
.some-child-element {
color : red ;
}
}
Support high-contrast mode
@include cdk-high-contrast ( active , off) {
.mat-button {
border : 1 px solid #fff !important ;
}
}
Document CSS classes
// The calendar icon button used to open the calendar pane.
.mat-datepicker-button { ... }
// Floating pane that contains the calendar.
.mat-datepicker-calendar-pane { ... }
Use classes over tag names
// ✅ Do
.mat-mdc-slider { ... }
// ❌ Don't
mdc-slider { ... }
Angular Specific
Host Bindings
@ Component ({
host: {
'(click)' : 'onClick($event)' ,
'[class.active]' : 'isActive' ,
}
})
✅ Prevents type preservation issues @ HostListener ( 'click' , [ '$event' ])
onClick ( event : Event ) { }
@ HostBinding ( 'class.active' )
isActive : boolean ;
❌ Can cause issues in non-browser environments
<!-- ✅ Do -->
< your-component >
< input >
</ your-component >
<!-- ❌ Don't -->
< your-component ></ your-component >
Let users interact directly with native inputs via ng-content.
Resources
TypeScript Style Guide Google’s official TypeScript guide
Contributing How to contribute to Angular Material
Dev Environment Set up your development environment
Component Harnesses Testing guidelines