8
votes

I am trying to use colors from my custom color pallette in my custom Angular Material theme for some other components.

For example a div with a mat-toolbar and an icon with margin, which should be filled with primary background color.

The Angular Material guides about theming says:

The theme file should not be imported into other SCSS files. This will cause duplicate styles to be written into your CSS output.

But in the guide with component theming, it says the following:

You can consume the theming functions and Material palette variables from @angular/material/theming. You can use the mat-color function to extract a specific color from a palette. For example:

// Import theming functions
@import '~@angular/material/theming';
// Import your custom theme
@import 'src/unicorn-app-theme.scss';

// Use mat-color to extract individual colors from a palette as necessary.
// The hue can be one of the standard values (500, A400, etc.), one of the three preconfigured
// hues (default, lighter, darker), or any of the aforementioned prefixed with "-contrast".
// For example a hue of "darker-contrast" gives a light color to contrast with a "darker" hue.
// Note that quotes are needed when using a numeric hue with the "-contrast" modifier.
// Available color palettes: https://www.google.com/design/spec/style/color.html
.candy-carousel {
  background-color: mat-color($candy-app-primary);
  border-color: mat-color($candy-app-accent, A400);
  color: mat-color($candy-app-primary, '100-contrast');
}

The theme is getting imported again in the component, where they extract the color with functions from the material theming.

I am confused, what is the right way, to use colors on non angular material components or event material components which have no color input?

2
Did you ever get a solution to this question?Daniel Lyons
Unfortunately not. Had to create a workaround with css classes.Florian Leitgeb

2 Answers

13
votes

I described it in this stack overflow answer.

You should put the theme related variables and the theme creation in separate files:

  • styles/_variables.scss
    • can be imported in all component scss files
    • uses @import '~@angular/material/theming'; to make material specific mixins available
    • contains typical theme variables like $primary, $accent and $warn
    • contains one or more $theme variables (e.g. via mat-light-theme($primary, $accent, $warn);)
  • theme.scss

    • should not be imported anywhere else
    • includes Angular Material core and theme

      @import 'variables';
      @include mat-core();
      @include angular-material-theme($theme);
      

To easily import the styles/_variables.scss into your component styles you have to add stylePreprocessorOptions to the angular.json file:

"styles": [
  "src/styles.scss",
  "src/theme.scss"
],
"stylePreprocessorOptions": {
  "includePaths": [
    "src/styles"
  ]
},

Now you can import you custom variables and theme variables in your component and use also material specific mixins like mat-color:

@import 'variables';

$background: map-get($theme, background);

.custom-class-a {
  background-color: mat-color($background, card);
  color: mat-color($mat-green, 700);
}
14
votes

It's late to answer to this question, but I had the same problem and spent a lot of time on trying to figure out how it works. The main problems were:

  • The Angular Material documentation on customizing own components doesn't tell you the whole story as Florian stated in his question.
  • I didn't find an example in an online discussion with all the required files and changes so that it worked.

I found two helpful examples on Stackblitz:

  • This one shows how to manipulate background and foreground elements from your theme.
  • This one shows how to switch between custom themes.

However, I needed something different:

  • I wanted to use own colors.
  • I wanted to use them in own components on elements like h1 or div.
  • Of course I wanted to avoid the duplication of styles which is recommended but not explained in the Angular Material theming docs.

This post on GitHub helped me the most. This discussion was also helpful in terms of switching from CSS to SCSS.

For anyone with the same problem I would like to share my solution so that you have it all in one spot:

1. Get your color definitions

Suppose you want to use #3F51B5 as primary and another one as accent color. Go to this site, enter each of your colors and download the definitions (pick "Angular JS 2 (Material 2)" and copy the content of $md-mcgpalette0: (___).

2. Create theme_variables.scss and put it in your src directory.

Insert your color definitions which you just downloaded.

@import "~@angular/material/theming";

$app-blue: (
    50 : #e8eaf6,
    100 : #c5cbe9,
    200 : #9fa8da,
    300 : #7985cb,
    400 : #5c6bc0,
    500 : #3f51b5,
    600 : #394aae,
    700 : #3140a5,
    800 : #29379d,
    900 : #1b278d,
    A100 : #c6cbff,
    A200 : #939dff,
    A400 : #606eff,
    A700 : #4757ff,
    contrast: (
        50 : #000000,
        100 : #000000,
        200 : #000000,
        300 : #000000,
        400 : #ffffff,
        500 : #ffffff,
        600 : #ffffff,
        700 : #ffffff,
        800 : #ffffff,
        900 : #ffffff,
        A100 : #000000,
        A200 : #000000,
        A400 : #ffffff,
        A700 : #ffffff,
    )
);

$app-yellow: ( 
    // repeat for your second color
);

$app-primary: mat-palette($app-blue, 500);
$app-accent: mat-palette($app-yellow, 500);

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

// Custom Sass colors vars (will be available in all the project)
$primary: mat-color($app-primary);
$accent: mat-color($app-accent);
$warn: mat-color($app-warn);

You could also separate the palette from the variable definitions into two different files but I left it like that.

3. Create theme.scss and put it in your src directory:

@import "~@angular/material/theming";
@import "./theme_variables.scss";
@import "./fonts/fonts.css"; // in case you have this file for your fonts

@include mat-core();

$app-theme: mat-light-theme($app-primary, $app-accent, $app-warn);

@include angular-material-theme($app-theme);

4. Create styles.scss and put it in your src directory:

@import "./theme.scss";

// add the rest of your global styles

5. Update angular.json:

... "styles": [
          "src/styles.scss",
          "src/theme.scss"
        ] ...

6. In your component, where you want to use the theme colors, rename the example.component.css-file to .scss and edit it:

@import "../../theme_variables.scss";

h1 { 
    color: $primary;
}

h2 { 
    color: $accent;
}
// put the rest of your styling

7. Update the style url in your example.component.ts file:

@Component({
  selector: "example",
  templateUrl: "./example.component.html",
  styleUrls: ["./example.component.scss"] // <-- update the file type
})

8. Switch to scss by deafult

Run ng config schematics.@schematics/angular:component.styleext scss to create scss files for new components in the future.

Update: If on component creation still no scss file is created, the reason might be that you have to configure scss extensions for all your projects. See this discussion for further information. What helped me: ng config projects.<projectname>.schematics.@schematics/angular:component.style scss


If you don't need the variables in all components, you can leave their css files like that. Whenever you want to use the theme colors in a component, change the css file to scss, import the theme variables and update the styleUrl in the component (step 6 + 7).

I am quite new to Angular and there are probably things you can do better. So anyone who has further suggestions, please let me know.