Search code examples
angular7angular-material-7

Style for non-ngcontent element


Angular adds tags without attributes for own components. In Angular 7 selectors /deep/, >>>, and ::ng-deep have got deprecated, so now I can't reach out to tags, that I describe in my makeup, via :host() and :host-context().

Original makeup:

<mat-expansion-panel>
  <mat-expansion-panel-header>expansion-panel-header>
  ...
</mat-expansion-panel>

Makeup after compiling:

<mat-expansion-panel _ngcontent-c13="" class="mat-expansion-panel">
  <mat-expansion-panel-header _ngcontent-c13=""></mat-expansion-panel-header>
  <div class="mat-expansion-panel-content">
    <div class="mat-expansion-panel-body">
      ...
    </div>
  </div>
</mat-expansion-panel>

There are some cases, what I get after compiling my SCSS:

1.
.mat-expansion-panel-body {
  padding: 0;
}

 |
 |
\ /
 V

.mat-expansion-panel-body[_ngcontent-c13] {
  padding: 0;
}



2.
:host-context() .mat-expansion-panel-body {
  padding: 0;
}

 |
 |
\ /
 V

[_nghost-c13]   .mat-expansion-panel-body[_ngcontent-c13] {
  padding: 0;
}



3.
:host() AND :host-context() {
  .mat-expansion-panel-body {
    padding: 0;
  }
}

 |
 |
\ /
 V

[_nghost-c13]   .mat-expansion-panel-body[_ngcontent-c13] {
  padding: 0;
}

but I want just

.mat-expansion-panel-body[_ngcontent-c13] {
  padding: 0;
}  

What must I do, please?


Solution

  • You generally can't rely on the _ngcontent-* attributes as they are dynamic and unpredictable. These attributes are part of how Angular 'scopes' the style so that style applied in one component does not affect style applied to the same item in another component. You can still limit style to a scope by applying a class or attribute to the outer component:

    HTML

    <mat-expansion-panel my-mat-expansion-panel>
      <mat-expansion-panel-header>...</mat-expansion-panel-header>
      ...
    </mat-expansion-panel>
    

    CSS

    .mat-expansion-panel[my-mat-expansion-panel] .mat-expansion-panel-body {
      padding: 0;
    }
    

    For your concerns, this is not a lot different than using the _ngcontent-* attribute if that were possible.

    You could also use whatever component your Angular Material component is in as part of the CSS selector to limit the scope:

    my-outer-component .mat-expansion-panel .mat-expansion-panel-body {
      padding: 0;
    }
    

    Note that your style needs to be in the global style sheet of course, not in a component's style.