Moshe
Moshe

Reputation: 2684

Angular Material custom colors

I would like to have access to more than 3 colors for my material theme. For example, I would like to add in $theme-success: mat-pallete($mat-green) to have a green success color in my Material components like md-checkbox color="success".

@import '~@angular/material/theming';
@include mat-core();

$theme-primary: mat-palette($mat-blue);
$theme-accent: mat-palette($mat-yellow, A400, A200, A600);
$theme-warn: mat-palette($mat-red);
$theme: mat-light-theme($theme-primary, $theme-accent, $theme-warn);

.body-light {
  @include angular-material-theme($theme);
}

Is this possible?

Upvotes: 3

Views: 8221

Answers (4)

Igor Kurkov
Igor Kurkov

Reputation: 5040

With angular 15 in 2023 you can use next mixin for applying color="success" and color="info":

mat-button-variants.scss

@use 'sass:map';
@use 'sass:meta';
@use '@angular/material' as mat;

$_ripple-opacity: 0.1;

// Applies a focus style to an mat-button element for each of the supported palettes.
@mixin _focus-overlay-color($config-or-theme, $variants) {
  $config: mat.get-color-config($config-or-theme);
  @each $variant, $variant-palette in $variants {
    &.mat-#{$variant} .mat-button-focus-overlay {
      background-color: mat.get-color-from-palette($variant-palette);
    }
  }
}

@mixin _ripple-background($palette, $hue, $opacity) {
  $background-color: mat.get-color-from-palette($palette, $hue, $opacity);
  background-color: $background-color;
  @if (meta.type-of($background-color) != color) {
    opacity: $opacity;
  }
}

@mixin _ripple-color($theme, $hue, $opacity, $variants) {
  @each $variant, $variant-palette in $variants {
    &.mat-#{$variant} .mat-ripple-element {
      @include _ripple-background($variant-palette, $hue, $opacity);
    }
  }
}

// Applies a property to an mat-button element for each of the supported palettes.
@mixin _theme-property($theme, $property, $hue, $variants) {
  $background: map.get($theme, background);
  $foreground: map.get($theme, foreground);

  @each $variant, $variant-palette in $variants {
    &.mat-#{$variant} {
      #{$property}: mat.get-color-from-palette($variant-palette, $hue);
    }

    &.mat-#{$variant} {
      &.mat-button-disabled {
        $palette: if($property == 'color', $foreground, $background);
        #{$property}: mat.get-color-from-palette($palette, disabled-button);
      }
    }
  }
}

@mixin color($config-or-theme, $variants) {
  $config: mat.get-color-config($config-or-theme);
  $foreground: map.get($config, foreground);
  $background: map.get($config, background);

  .mdc-button:not(:disabled),
  .mat-mdc-icon-button:not(:disabled),
  .mat-mdc-stroked-button:not(:disabled) {
    @include _theme-property($config, 'color', text, $variants);
    @include _focus-overlay-color($config, $variants);
  }

  .mat-mdc-flat-button:not(:disabled),
  .mat-mdc-raised-button:not(:disabled),
  .mat-mdc-unelevated-button:not(:disabled),
  .mat-mdc-fab:not(:disabled),
  .mat-mdc-mini-fab:not(:disabled) {
    @include _theme-property($config, 'color', default-contrast, $variants);
    @include _theme-property($config, 'background-color', default, $variants);
    @include _ripple-color($config, default-contrast, $_ripple-opacity, $variants);
  }
}

you should define a scss map object with palettes for success and info:

material-theme-index.scss:

@use './mat-button-variants' as button-variants;

...

$theme-success: mat.define-palette($palette-success);
$theme-info: mat.define-palette($palette-info);

$variants-theme: (
  success: $theme-success,
  info: $theme-info,
);
// and include mixin above
@include button-variants.color($main-theme, $variants-theme);

and now it will work as should in <button mat-raised-button color="success">Click me</button>

PS: if you use material lower versions like 14 and below please rename mdc to mat in classes due to latest breaking changes in material v15 with extra classes prefixes mdc. Current example works for angular 15+.

Upvotes: 1

I did the following to make full use of the button features

  1. I created a palette on my main theme file, _theme.scss

@import '~@angular/material/theming';
// Plus imports for other components in your app.

// Include the common styles for Angular Material. We include this here so that you only
// have to load a single css file for Angular Material in your app.
// Be sure that you only ever include this mixin once!
@include mat-core();

// Define the palettes for your theme using the Material Design palettes available in palette.scss
// (imported above). For each palette, you can optionally specify a default, lighter, and darker
// hue. Available color palettes: https://material.io/design/color/
$my-app-primary: mat-palette($mat-deep-purple);
$my-app-accent:  mat-palette($mat-amber, A200, A100, A400);
$my-app-green:  mat-palette($mat-green);  // <------ My new palette

// The warn palette is optional (defaults to red).
$my-app-warn:    mat-palette($mat-red);

// Create the theme object (a Sass map containing all of the palettes).
$my-app-theme: mat-light-theme($my-app-primary, $my-app-accent, $my-app-warn);

// Include theme styles for core and each component used in your app.
// Alternatively, you can import and @include the theme mixins for each component
// that you are using.
@include angular-material-theme($my-app-theme);

@import './buttons';

  1. I defined my override in _buttons.scss

.mat-raised-button {
  &.mat-green {
    color: mat-color($my-app-green, darker-contrast);
    background-color: mat-color($my-app-green, default);
    
    &[disabled] {
      color: mat-color($mat-light-theme-foreground, disabled-button);
      background-color: mat-color($mat-light-theme-background, disabled-button);
    }

    .mat-ripple-element {
      @include _mat-button-ripple-background($my-app-green, darker-contrast, $_mat-button-ripple-opacity);
    }
  }
}

Everything I needed to figure these out are in \node_modules\@angular\material\_theming.scss

And a starting point from here

Upvotes: 1

DannyDDev
DannyDDev

Reputation: 86

Also, if you really need an extra color you can create class in styles.scss (or.css) or anywhere in your style sheets.

.mat-buttonSuccess{
    background-color: #ffff00;
    color: #000;
}

and then call it as color same way as primary, accent and warn.

<button mat-raised-button color="buttonSuccess">Success</button>

Upvotes: 4

Will Howell
Will Howell

Reputation: 3715

The color bindings only support primary, accent, and warn.

If the coloring is simple (for checkbox, it's just .mat-checkbox-background and .mat-ripple-element), you can use the palette yourself:

$theme-success: mat-palette($mat-green);

.mat-checkbox-ripple .mat-ripple-element {
  background-color: mat-color($theme-success, 0.26);
}

You could probably also get away with making 2 themes, where the second one uses your success color for primary

$theme-primary: mat-palette($mat-blue);
$theme-accent: mat-palette($mat-yellow, A400, A200, A600);
$theme-warn: mat-palette($mat-red);
$theme: mat-light-theme($theme-primary, $theme-accent, $theme-warn);

$theme-success: mat-palette($mat-green);
$theme2: mat-light-theme($theme-success, $theme-accent, $theme-warn);

.body-light {
  @include angular-material-theme($theme);
}

.component-success {
  @include angular-material-theme($theme2);
}

Upvotes: 6

Related Questions