angularangular-materialcss-selectorsangular9angular-ivy

Angular 9 (Ivy): CSS class^ attribute selectors stops working with angular material components


I am currently updating an Angular project from v8 to v9, and I have discovered an issue with using CSS class attributes together with Angular Material components. I have also updated to Material v9.

With this simplified HTML,

// Example List 1
<mat-nav-list class="example-list-1">
  <mat-list-item> SOME HTML.. </mat-list-item>
</mat-nav-list>

// Example List 2
<div class="example-list-2">
  <mat-list-item> SOME HTML.. </mat-list-item>
</div>

the following SCSS,

[class^="example-list"] {
  mat-list-item {
    SOME SCSS..
  }
}

is only adding style to the <mat-list-item> in Example List 2, where <div> is being used.

It works fine if I, for example, use id instead of class in both HTML and SCSS, but I would prefer not to have to do a lot of tinkering with the code.

Update

I have also found out it works fine if I disable Ivy.

"angularCompilerOptions": {
    "enableIvy": false
 }

Why is it not working with Ivy? Is this expected behavior?


Solution

  • I think you faced a bug that was introduced with Ivy https://github.com/angular/angular/issues/33111

    The issue here is the wrong order of adding css classes.

    MatNavList component has a host property binding within metadata:

    @Component({
      selector: 'mat-nav-list',
      host: {
        'role': 'navigation',
        'class': 'mat-nav-list mat-list-base',
      },
      ...
    })
    export class MatNavList
    

    https://github.com/angular/components/blob/74685883ec16782d172a4505348eef6f2003a31b/src/material/list/list.ts#L66

    Before Ivy your class was added first to class attribute of element:

    <mat-nav-list class="example-list-1 mat-nav-list mat-list-base"
    

    with early Ivy version it became the last added class:

    <mat-nav-list class="mat-nav-list mat-list-base example-list-1"
    

    As a result your selector doesnt work for second case. But there is an alternative:

    [class*="example-list"] {
      ...
    }