0

I’ve created a custom button using an attribute selector (which I want to keep in place for maintaining native button functionality), but I’m struggling to incorporate the Angular Material mat-flat-button directive into it. I’ve searched around online and tried different AI tools, but I haven’t found any relevant solutions. Am I trying to do the impossible here?

Here’s my current button implementation:

import { Component } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';

@Component({
  selector: 'button[m-primary-btn]',
  template: '<ng-content></ng-content>',
  styleUrls: ['./button.component.scss'],
  standalone: true,
  imports: [MatButtonModule],
  host: {
    'class': 'primary'
  }
})
export class PrimaryButtonComponent {}

I’ve attempted to add the mat-flat-button directive to the selector and template, but with no success. Does anyone have any suggestions? Also, I’d like to avoid manually adding the Material directive to each button instance.

2 Answers 2

1

Congratulations! The above decision from Balkishan Dhaker will not let you create the bindings and styles you want.

I recommend you take a slightly different approach to designing such components.

Component.ts

import { ChangeDetectionStrategy, Component, Input } from '@angular/core';

@Component({
  selector: 'help-component',
  templateUrl: './help-page.component.html',
  styleUrl: './help-page.component.scss',
  changeDetection: ChangeDetectionStrategy.OnPush,
  standalone: false,
})
export class HelpPageComponent {
  @Input() public type?: AllowedInputTypes = "flat"

  constructor() { }
}

type AllowedInputTypes = 'basic' | 'flat' | 'raised'

component.html

<ng-container [ngSwitch]="type">
    <!-- Raised -->
    <ng-container *ngSwitchCase="'raised'">
        <button mat-raised-button>
            <ng-container [ngTemplateOutlet]="content"></ng-container>
        </button>
    </ng-container>
    <!-- / Raised / -->

    <!-- / Flat / -->
    <ng-container *ngSwitchCase="'flat'">
        <button mat-flat-button>
            <ng-container [ngTemplateOutlet]="content"></ng-container>
        </button>
    </ng-container>
    <!-- Flat -->

    <!-- Basic -->
    <ng-container *ngSwitchCase="'basic'">
        <button mat-button>
            <ng-container [ngTemplateOutlet]="content"></ng-container>
        </button>
    </ng-container>
    <!-- / Basic / -->
</ng-container>

<ng-template #content>
    <ng-content></ng-content>
</ng-template>

You need to call the component as follows:

other.component.html

<!-- Default -->
<help-component>MyFlatButton</help-component>
<!-- / Default / -->

<help-component [type]="'basic'">MyBasicButton</help-component>
<help-component [type]="'flat'">MyFlatButton</help-component>
<help-component [type]="'raised'">MyRaisedButton</help-component>

Such a solution will allow you to centralize your button settings and avoid other, redundant logic for mat-button rendering

[Stylization] Use mixins to style mat components. see the documentation on the Angular material site.

usage example: help-page.component.scss

@use '@angular/material' as mat;

:host {}

:host.custom-flat-style {
    @include mat.button-overrides((protected-container-color: red));
}

Call a custom component using mixins:

<help-component [type]="'raised'" class="custom-flat-style">2344</help-component>
Sign up to request clarification or add additional context in comments.

9 Comments

Hey mate thanks for example. I was using this way of wrapping Angular Material buttons, but I managed to try implement it more native way, so I don't lose native button functionalities, right? I actually managed to make this work, but now I'm facing another issue. Angular MatButton template has some additional HTML, not just ng-content which is managing some styles for ripple, icon buttons, etc.. So now I'm trying to find a way of inheriting MatButton HTML file because we cannot access it from our Components :) Got any idea?
@Freezy Starting with Angular v19, you can use mixins to override styles. For example, in the help-page.component component, declare the classes and create the required number of mixins to change button styles.
It's not about styles overrides, check MatButton source code, they have button.html which has multiple span elements with different styles attached. With my implementation I somehow don't inherit that HTML, only child I has is pure text that I pass inside button, but when you use mat-flat-button selector, inside button you can see multiple spans. I will create stackblitz example tomorrow, so I can show you.
@Freezy I supplemented my answer with an example of custom button styling. You can create different call scenarios for each of the mixins. These can be class names (as mentioned in the answer), or other logic that will add mixins
"It's not about styles overrides, check MatButton source code, they have button.html which has multiple span elements with different styles attached. With my implementation I somehow don't inherit that HTML. I caj make stackblitz example tomorrow, so I can show you" As you implemented, you will not be able to inherit these styles. Angular Material components or directives must be used directly in your HTML file. These are not ordinary attributes of styles, and it will not work to generate them dynamically in the way you mentioned.
|
0

You can manually add the attribute in the onInit or in component host try below to use as host

@Component({
  selector: 'button[m-primary-btn]',
  template: `<ng-content></ng-content>`,
  styleUrls: ['./m-primary-btn.component.scss'],
  standalone: true,
  imports: [MatButtonModule],
  host: {
    'class': 'mat-flat-button',
    '[attr.mat-flat-button]': "''",
    '[attr.color]': 'color',
  },
})
export class MPrimaryBtnDirective {
  @Input() color: 'primary' | 'accent' | 'warn' = 'primary';
}

1 Comment

Thanks for the example, I have tried it and attribute was set but button didn't inherit angular material styles. Have you tried it or just guessing?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.