components: Theming your own component doc incorrectly references pre-built theme

Bug, feature request, or proposal:

Bug/Incorrect Documentation

What is the expected behavior?

According to the theming your components documentation you should be able to use pre-built themes with your custom components

// Import a pre-built theme
@import '~@angular/material/prebuilt-themes/deeppurple-amber.css';
// Import your custom input theme file so you can call the custom-input-theme function
@import 'app/candy-carousel/candy-carousel-theme.scss';

// Using the $theme variable from the pre-built theme you can call the theming function
@include candy-carousel-theme($theme);

What is the current behavior?

The Sass compiler throws an error : Undefined variable: "$theme"

What are the steps to reproduce?

Componet Theme scss:

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

@mixin my-component-theme($theme) {
    $primary: map-get($theme, primary);
    my-component{
        background-color: mat-color($primary);
    }
}

Styles.scss

@import '~@angular/material/prebuilt-themes/indigo-pink.css';
@import './path/to/my-component.theme';
@include my-component-theme($theme);

What is the use-case or motivation for changing an existing behavior?

While this isn’t as much of a problem with components that are defined in an application as you can define your own theme, it IS a major issue when creating component libraries that will be consumed by other applications that may choose to use a pre-built theme.

Which versions of Angular, Material, OS, TypeScript, browsers are affected?

Angular: 4.1.3 Material: Beta 6

Is there anything else we should know?

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Reactions: 7
  • Comments: 23 (8 by maintainers)

Most upvoted comments

Thank you all to the contributions to this thread, after fighting with the docs this was a very useful resource. I would appreciate confirmation that my understanding of the approach is correct, and specifically does not import the mat-core and angular-material-theme multiple times.

theme_variables.scss

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

// Define the palettes for your theme using the Material Design palettes available in palette.scss
$app-primary: mat-palette($mat-blue-grey);
$app-accent:  mat-palette($mat-grey);
$app-warn:    mat-palette($mat-deep-orange);

// 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);

theme.scss

@import '~@angular/material/theming';
@import "~theme_variables.scss";

@include mat-core();
$app-theme: mat-light-theme($app-primary, $app-accent, $app-warn);
@include angular-material-theme($app-theme);

styles.scss

@import "theme.scss";

...

nav.component.scss

@import "~theme_variables.scss";

.primary {
    color: $primary;
}

.angular-cli.json

"styles": [
   "styles.scss"
]

I suppose my concern is that the nav component imports the theme_variables which imports angular/material/theming but I cannot see how to accomplish without.

I must agree that the docs behind theming custom components are pretty confusing.

I want to create a custom component (much like angular button etc.) which would work with the current theme’s $primary & $accent colors. This component would be packaged and then consumed by target app (so the component should not have a theme, but use the theme of target app).

So what is the correct way to do this?

This is in addition to @michael-gregson’s solution above, specifically so that we do not have to import theme_variables.scss from the custom component’s theme scss file.

  • Declare a theme scss (nav.component.theme.scss), typically in the same location as your custom component.
  • Import and include the custom component theme’s mixin in theme.scss.
  • It might be useful to know that nav.component.theme.scss is NOT declared as the custom component’s styleUrls. That was not immediately obvious to me when learning to theme custom components.

nav.component.theme.scss

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

@mixin nav-component-theme($theme) {
  $primary: map-get($theme, primary);
  $accent: map-get($theme, accent);

  // your custom component's selector
  .nav {
    background-color: mat-color($primary);
    border-color: mat-color($accent, A400);
  }
}

theme.scss:

@import '~@angular/material/theming';
@import 'theme-variables';

@include mat-core();

$app-theme: mat-light-theme($palette-primary, $palette-accent, $palette-warn);
@include angular-material-theme($app-theme);

@import "components/nav.component.theme";
@include page-content-theme($app-theme);

I would also like to feedback to Angular Material team that the current theming your custom components page is causing more harm than good to those trying to theme custom components.

How about just remove the page until it has been updated to actually work?

my solution just do not use pre-build theme, but we can customize one like it you can find all color in ~@angular/material/_theming.scss

my example:

src\theme_variables.scss


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

// deep-purple

$app-primary: mat-palette($mat-deep-purple);
$app-accent:  mat-palette($mat-amber, A200, A100, A400);
$app-warn:    mat-palette($mat-red);

$primary: mat-color($app-primary);
$primary-contrast: mat-color($app-primary, default-contrast);
$accent: mat-color($app-accent);
$accent-contrast: mat-color($app-accent, default-contrast);
$warn: mat-color($app-warn);
$warn-contrast: mat-color($app-warn, default-contrast);

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

$app-text: mat-color(map-get($app-theme, foreground), text);

src\theme.scss


@import '~@angular/material/theming';
@import "~theme_variables.scss";
@include mat-core();
@include angular-material-theme($app-theme);

src\style.css it’s nothing,it’s empty ,don’t import ~@angular/material/prebuilt-themes/deeppurple-amber.css


/* @import '~@angular/material/prebuilt-themes/deeppurple-amber.css'; */

src\app\file-card\file-card.component.scss


@import "~theme_variables.scss";
.primary{
    background-color: $primary;
    color: $primary-contrast;
}

src\app\file-card\file-card.component.html <div class="primary"> some text </div> .angular-cli.json


{
  "apps": [
    {
      "styles": [
        "theam.scss",
        "styles.css"
      ]
    }
]

@Parent5446 I don’t know if it’s the correct procedure, but the cleaner way I have found is to create some color variables in theme.scss using mat-color() function. This way I’m able to use the colors through all the project without problems:

// _variables.scss
@import '~@angular/material/theming';

// Define the palettes for your theme using the Material Design palettes available in palette.scss
$app-primary: mat-palette($mat-grey);
$app-accent:  mat-palette($mat-light-blue);
$app-warn:    mat-palette($mat-pink);

// 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);
$otherColor: #99999;
// your.component.scss
@import "~_variables.scss";
.selected {
  background-color: $accent;
}
  • Don’t forget to include theme.scss in the .angular-cli.json:
// .angular-cli.json
{
...
  "apps": [{
  ...
  "styles": ["_variables.scss"]
  }]
}

Thanks to @willshowell for point me out that importing directly the theme.scss would include mat-core and angular-material-theme in every importing .scss file. As he says, the way to go is create a separate file for this global vars.

@e11en As the error says, $primary is a map and not a color. You must to use mat-color function included in angular/material/theming.

I recommend you to browse the material components to learn how to use that variables properly. E.g: https://github.com/angular/material2/blob/master/src/lib/button/_button-theme.scss

@michael-gregson you’re good!