'How To Access Angular Material Colors In Components?
In angular material, we can pass colors to angular material components as attribute, for example
<button mat-raised-button color="primary">Example</button>
I'm using multiple angular material themes, which changes dynamically.
Required Behaviour: Changing color of my custom components dynamically with theme change.
I want something like this:
<app-footer color="primary"></app-footer>
How to get color in my custom component?
What I tried
I had a input property in my component
@Input() color;
and tried to pass color in component
<app-footer color="primary"></app-footer>
But it didn't worked for me.
How to achieve this?
==UPDATE==
Explanation: Below lines of code are from button.ts file of angular material from its github repository
/**
* Material design button.
*/
@Component({
moduleId: module.id,
selector: `button[mat-button], button[mat-raised-button], button[mat-icon-button],
button[mat-fab], button[mat-mini-fab], button[mat-stroked-button],
button[mat-flat-button]`,
exportAs: 'matButton',
host: {
'[attr.disabled]': 'disabled || null',
'[class._mat-animation-noopable]': '_animationMode === "NoopAnimations"',
},
templateUrl: 'button.html',
styleUrls: ['button.css'],
inputs: ['disabled', 'disableRipple', 'color'],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
Link to file: Button.ts
Here you can see, it takes color as input. Similarly, I have also taken color as input in my footer component. Now with <app-footer color="primary"></app-footer>
I got primary string as input in my footer component.
How to get color hex from this to set background color of my footer component. Please note, primary color changes dynamically with theme change, therefore, I cannot hard-code color.
Solution 1:[1]
I found its solution. I'm posting it here so that if someone else requires similar behavior in their angular app, they can get it, in the following way.
I created a mixin for footer
@mixin footer-theme($theme) {
$primary: map-get($theme, primary);
$accent: map-get($theme, accent);
$warn: map-get($theme, warn);
$background: map-get($theme, background);
$foreground: map-get($theme, foreground);
app-footer {
.footer-primary {
background-color: mat-color($primary);
}
.footer-accent {
background-color: mat-color($accent);
}
}
}
app-footer
is a component selector and .footer-*
is a class of footer component to whom I want to apply the primary/accent background color.
In the footer component, color
is an input. We need to pass color value while embedding the footer component in the following way.
For the primary background color:
<app-footer color="primary"></app-footer>
For the accent background color:
<app-footer color="accent"></app-footer>
In the footer HTML file:
<div [ngClass]="{'footer-primary': color === 'primary', 'footer-accent': color === 'accent'}">
/*footer code here...*/
</div>
Then I included footer mixin in app_theme.scss file which has multiple themes
@import '~@angular/material/theming';
@import './app/shared/footer/footer-theme';
@include mat-core();
$primary1: mat-palette($mat-teal, 500);
$accent1: mat-palette($mat-green, A200, A100, A400);
$warn1: mat-palette($mat-red);
$theme1: mat-light-theme($primary1, $accent1, $warn1);
@include angular-material-theme($theme1);
@include footer-theme($theme1);
// SECOND THEME
$primary2: mat-palette($mat-indigo, 500);
$accent2: mat-palette($mat-blue, A200, A100, A400);
$warn2: mat-palette($mat-red);
$theme2: mat-light-theme($primary2, $accent2, $warn2);
.second-theme {
@include angular-material-theme($theme2);
@include footer-theme($theme2);
}
In app.component.html
<div [ngClass]="{'second-theme' : isSecondTheme}">
<div class="mat-app-background">
<router-outlet></router-outlet>
</div>
</div>
Here isSecondTheme
is a boolean, when true
second theme is applied, otherwise default theme. Just change boolean at runtime.
You can modify it to have more than two themes.
Solution 2:[2]
You need to actually set the [color]
property on the Angular Material component.
E.g.
color: string = 'primary'
Html:
<button [color]="color">My Button</button>
I've created a minimal example for your here.
Solution 3:[3]
A little bit late but maybe somebody else can use it. Here's how I did it. i needed the warn color so I could use it on one of my own elements.
Html:
//This is a dummy element, invisible to the user.
<mat-icon color="warn" [style.display]="'none'" #warnIconButton>home</mat-icon>
Ts:
@ViewChild('warnIconButton') _warnIconButton: MatButton
_warnColor:string = 'myFallbackColor'
ngAfterViewInit() {
const warnNativeElement = this._warnIconButton._elementRef?.nativeElement
this._warnColor = getComputedStyle(warnNativeElement)?.color
}
Solution 4:[4]
Angular Material Palette is a SASS map. It is like Map object in Javascript. So you can achieve getting colors from material by generating classes or even CSS variables.
@use '../palette';
@mixin generateColors($prefix, $palette) {
$colors-map: ();
@each $key, $value in $palette {
@if $key !=contrast {
.app-#{$prefix}-#{$key} {
color: map-get($palette, $key);
}
$map: ();
$map: map-merge($map, ($key: $value));
$colors-map: map-merge($colors-map, $map);
}
}
:root {
@each $key, $value in $colors-map {
--app-#{$prefix}-#{$key}: #{$value};
}
}
}
@mixin generate-material-classes {
@include generateColors(primary, $youtube-primary);
@include generateColors(accent, $youtube-accent);
@include generateColors(warning, $youtube-warning);
}
In your styles.scss:
import './generate-css-classes';
@include generate-material-classes();
This would generate CSS classes and CSS variables like below:
Then use like classes. For example,
<h1 class="app-primary-60 title"> Product title </h1>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | ViqMontana |
Solution 3 | ShanieMoonlight |
Solution 4 |