Bug/Incorrect Documentation
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);
The Sass compiler throws an error : Undefined variable: "$theme"
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);
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.
Angular: 4.1.3
Material: Beta 6
Pre-built === just CSS (not sass)
You're trying to import a sass variable from already-compiled CSS. You want @angular/material/theming
, as indicated in the documentation.
Ok so the documentation is just wrong then? and there is no way to make a component library work with pre-built themes?
@myrddraall AFAICT you're correct on both accounts. Since the prebuilt themes are just css, you won't be able to use them in a custom component library.
I don't know why the documentation says to import the prebuilt theme. I ran through the blame of that file and it looks like it just slipped through the review
Ah, I see what you're referencing now. The example further down looks like a bad copy-paste.
Can somebody in the meantime tell me how to use $primary in my components scss file?
I've created this theme.scss file
@import '~@angular/material/theming'; @include mat-core(); $primary: mat-palette($mat-indigo); $accent: mat-palette($mat-pink, A200, A100, A400); $warn: mat-palette($mat-red); $theme: mat-light-theme($primary, $accent, $warn); @include angular-material-theme($theme);
and reference it in my app.component.scss file
@import '../assets/style/theme.scss'; .nav-wrapper { background-color: $primary; }
but I get this error msg which I can't make any sense of
ERROR in ./src/app/app.component.scss Module build failed: undefined ^ (50: #e8eaf6, 100: #c5cae9, 200: #9fa8da, 300: #7986cb, 400: #5c6bc0, 500: #3f51b5, 600: #3949ab, 700: #303f9f, 800: #283593, 900: #1a237e, A100: #8c9eff, A200: #536dfe, A400: #3d5afe, A700: #304ffe, contrast: (50: rgba(0, 0, 0, 0.87), 100: rgba(0, 0, 0, 0.87), 200: rgba(0, 0, 0, 0.87), 300: white, 400: white, 500: rgba(255, 255, 255, 0.87), 600: rgba(255, 255, 255, 0.87), 700: rgba(255, 255, 255, 0.87), 800: rgba(255, 255, 255, 0.87), 900: rgba(255, 255, 255, 0.87), A100: rgba(0, 0, 0, 0.87), A200: white, A400: white, A700: rgba(255, 255, 255, 0.87)), default: #3f51b5, lighter: #c5cae9, darker: #303f9f, default-contrast: rgba(255, 255, 255, 0.87), lighter-contrast: rgba(0, 0, 0, 0.87), darker-contrast: rgba(255, 255, 255, 0.87), "50-contrast": rgba(0, 0, 0, 0.87), "100-contrast": rgba(0, 0, 0, 0.87), "200-contrast": rgba(0, 0, 0, 0.87), "300-contrast": white, "400-contrast": white, "500-contrast": rgba(255, 255, 255, 0.87), "600-contrast": rgba(255, 255, 255, 0.87), "700-contrast": rgba(255, 255, 255, 0.87), "800-contrast": rgba(255, 255, 255, 0.87), "900-contrast": rgba(255, 255, 255, 0.87), "A100-contrast": rgba(0, 0, 0, 0.87), "A200-contrast": white, "A400-contrast": white, "A700-contrast": rgba(255, 255, 255, 0.87), "contrast-contrast": null) isn't a valid CSS value. in E:\ERP3\node_modules\@angular\material\_theming.scss (line 1089, column 14) @ ./src/app/app.component.ts 20:17-48 @ ./src/app/app.module.ts @ ./src/main.ts @ multi webpack-dev-server/client?http://localhost:4200 ./src/main.ts
@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
@e11en Try this:
@import '../assets/style/theme.scss';
$primary: map-get($theme, primary);
.nav-wrapper {
background-color: $primary;
}
However, you should really be arranging your theme.scss file differently. When you're importing it into your component stylesheets, you're calling @include mat-core()
each time, which duplicates a lot of styles. See the warning here.
Maybe instead try something like this
_custom_theme.scss
$primary: ...
$accent: ...
$theme: ...
required.scss (add this file to your global styles and never import it into anything)
@import '~@angular/material/theming';
@import 'custom_theme';
@include angular-material-theme($theme);
@include mat-core();
app.component.scss
@import 'custom-theme';
...
@ocarreterom
ah now I get it, thanks!
@willshowell
Thank you for your help, I think I'm starting to understand now
I can use the method in the docs but using Material Design 2 (MD2) when installed in the node_modules there are several angular material themes SCSS files, i don't know if they used the same files from this repository but i can do the next things in my Angular CLI project:
/**
* Angular Material Theme
*/
@import '~@angular/material/prebuilt-themes/deeppurple-amber.css';
/**
* Angular MD2 Theme
*
* TODO: this must not be the way for changing the color of controls in MD2
* reffers to issue https://github.com/Promact/md2/issues/253
*
* TODO: in the near future replace all components of MD2 with standard Angular Material 2
* components; at this time the datepicker in Angular Material 2 is too simple.
*/
@import '~md2/core/theming/prebuilt/deeppurple-amber.scss';
@import 'assets/customs/md2/datepicker.scss';
@include md2-datepicker-theme($theme);
@import '~@angular/material/theming';
@mixin md2-datepicker-theme($theme) {
// Extract whichever individual palettes you need from the theme.
$primary: map-get($theme, primary);
$accent: map-get($theme, accent); // Use mat-color to extract individual colors from a palette as necessary.
.md2-calendar-header {
background-color: mat-color($primary) !important;
}
.md2-calendar-body-selected {
background-color: mat-color($primary) !important;
}
.md2-calendar-body-today:not(.md2-calendar-body-selected) {
border-color: mat-color($primary) !important;
}
}
So what is the correct procedure if the docs are incorrect? Create your own theme from scratch?
@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;
}
// .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.
@aleixsuau as a note, every file that imports theme.scss
will also import all the mat-core
and angular-material-theme
styles. You should separate them so that the @include
s are only called once.
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.
@michael-gregson you're good!
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.
nav.component.theme.scss
), typically in the same location as your custom component.theme.scss
.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?
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?
@bezysoftware have you found out how to do this ?
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:
srctheme_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);
srctheme.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"
]
}
]
@shiftonetothree thanks for your perfect answer !!
That works as long as you have a component within your app. If you want to package your component as an npm package, this doesn't work because your scss get compiled to css and embedded into the generated javascript.
So how those pre-built themes are generated, and can we use the variables defined in them?
This was resolved in #13435
This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.
Read more about our automatic conversation locking policy.
_This action has been performed automatically by a bot._
Most helpful comment
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
theme.scss
styles.scss
nav.component.scss
.angular-cli.json
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.