angular / components

Component infrastructure and Material Design components for Angular
https://material.angular.io
MIT License
24.33k stars 6.74k forks source link

Allow overriding of theme background and foreground colors #6244

Open mackelito opened 7 years ago

mackelito commented 7 years ago

Bug, feature request, or proposal:

proposal

What is the expected behavior?

Add documentation on how to set background in a custom theme to https://material.angular.io/guide/theming

What is the current behavior?

No docs

What are the steps to reproduce?

https://material.angular.io/guide/theming

Providing a Plunker (or similar) is the best way to get the team to see your issue. Plunker template: https://goo.gl/DlHd6U

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

Makes it easier to customise themes

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

Is there anything else we should know?

literalpie commented 6 years ago

Should developers be encouraged to set background colors of a theme? Or do we just want documentation on using the background color from a theme?

put differently: Do we want to (a) show people how to change the value of map-get($theme, background), or do we want to (b) document that map-get($theme, background) can be used?

fabienbranchel commented 6 years ago

@literalpie : I'd like to know how to set background colors of a theme when I create it.

literalpie commented 6 years ago

@fabienbranchel If you want to set the background colors, you likely want to customize the entire background and foreground palette by emulating the mat-light-theme or mat-dark-theme functions with your own replacement. Your replacement would include your own palettes instead of the mat-light-theme-foreground and background palettes.

example: https://stackblitz.com/edit/angular-material-custom-background?file=theme.scss

I don't know if this method is recommended or officially supported - therefore, I'm not sure if it should be added to the documentation. It seems to me like it would be a better fit for a blog post.

intellix commented 5 years ago

Would be nice if those 2 functions were similar to how red has defaults to allow overriding without copy/pasting:

// Creates a container object for a light theme to be given to individual component theme mixins.
@function mat-light-theme($primary, $accent, $warn: mat-palette($mat-red), $foreground: mat-palette($mat-light-theme-foreground), $background: mat-palette($mat-light-theme-background)) {
  @return (
    primary: $primary,
    accent: $accent,
    warn: $warn,
    is-dark: false,
    foreground: $foreground,
    background: $background,
  );
}

// Creates a container object for a dark theme to be given to individual component theme mixins.
@function mat-dark-theme($primary, $accent, $warn: mat-palette($mat-red), $foreground: mat-palette($mat-dark-theme-foreground), $background: mat-palette($mat-dark-theme-background)) {
  @return (
    primary: $primary,
    accent: $accent,
    warn: $warn,
    is-dark: true,
    foreground: $foreground,
    background: $background,
  );
}

Or better yet, just don't use those functions:

$my-dark-theme: (
  primary: $my-primary,
  accent: $my-accent,
  warn: $my-warn,
  is-dark: true,
  foreground: $my-dark-theme-foreground,
  background: $my-dark-theme-background,
);

$my-light-theme: (
  primary: $my-primary,
  accent: $my-accent,
  warn: $my-warn,
  is-dark: false,
  foreground: $my-light-theme-foreground,
  background: $my-light-theme-background,
);

To be honest whilst reading into all of the helpers the mat-light-theme() and mat-dark-theme() functions add an extra layer of complexity that doesn't add anything IMO

ktsangop commented 5 years ago

I have also struggled to find a way to set the app background, and unfortunately the proposed solutions do not work if the app is not wrapped in a material component.

For example, in @literalpie 's example, the app is wrapped inside a mat-sidenav-container component.

The only way i have found to set the background for app-root, is to inculde the following in your styles.scss file (or whatever the name of the file that you declare on your angular.json definition)

app-root {
  background: map-get($mat-dark-theme-background, background );
}

That will work, provided that you have declared the $mat-dark-theme-background map, and it is helpful because you keep your background color declared in one place (theme.scss).

Of course you can provide any color, that is independent of the theme you have created, but this might be harder to maintain.

literalpie commented 5 years ago

@ktsangop I think you're missing this:

Finally, if your app's content is not placed inside of a mat-sidenav-container element, you need to add the mat-app-background class to your wrapper element (for example the body). This ensures that the proper theme background is applied to your page.

source

literalpie commented 5 years ago

@intellix

To be honest whilst reading into all of the helpers the mat-light-theme() and mat-dark-theme() functions add an extra layer of complexity that doesn't add anything IMO

Are you saying that instead of having the two functions, someone would use the dark theme by passing the foreground and background? I could get on board with that.

ktsangop commented 5 years ago

@ktsangop I think you're missing this:

Finally, if your app's content is not placed inside of a mat-sidenav-container element, you need to add the mat-app-background class to your wrapper element (for example the body). This ensures that the proper theme background is applied to your page.

source

🤦‍♂ OK, i have totally missed that! 🤣

FWIW, my solution, applies the background color even before the app.component is bootstraped, which in my case makes a custom loading spinner i have, being displayed using the theme background color.

Instead, adding the mat-app-background class to the <body> does not have the same effect.

prabhat22 commented 5 years ago

i am trying to use angular material with a theme built in scss,angular,bootstrap , i have install it using npm and add all the neccessary files, also it is not showing any error yet i am not able to use it components

the-blackpirate commented 4 years ago

Just add Material theming in your angular project.

ng add @angular/material

then choose custom theming option and paste the below code you will get black dark theming and if you wanna customize material color scheme then go to https://material.io and go material color palette and select your custom color scheme for your navbar and button(other components).

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

$custom-typography: mat-typography-config( $font-family: "-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif" );

@include mat-core($custom-typography);

$your-app-name-primary: mat-palette($mat-purple, 200); $your-app-name-accent: mat-palette($mat-teal, 200); $your-app-name-warn: mat-palette($mat-red); $your-app-name-theme: mat-dark-theme( $your-app-name-primary, $your-app-name-accent, $your-app-name-warn );

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

nair-ayush commented 4 years ago

Just found this thread. I've been trying to figure out themes for a long time. Couldn't find a concrete solution until now. Making it work by adding <mat-sidenav-container> over the app. So thank you @literalpie . But can you give an example of how to add the mat-app-background to the body element?

However, if I don't have enough content on the window then the rest of the background remains white(default color) only. So you would need to modify the style of <mat-sidenav-container> to max out it's height. You can see the app.component.css to look at what I've done.

I have applied the theme toggle in my header and as per Angular Material docs, added an extra class to the div wrapper by adding an id and modifying it's style in theme.service.ts.

custom_theme.scss

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

// LIGHT THEME

$light-primary: mat-palette($mat-indigo);
$light-accent: mat-palette($mat-yellow, A200, A100, A400);
$light-warn: mat-palette($mat-red);
$light-theme: mat-light-theme($light-primary, $light-accent, $light-warn);
@include angular-material-theme($light-theme);

// DARK THEME

$dark-primary: mat-palette($mat-grey);
$dark-accent: mat-palette($mat-amber, A200, A100, A400);
$dark-warn: mat-palette($mat-red);
// Create the theme object (a Sass map containing all of the palettes).
$dark-theme: mat-dark-theme($dark-primary, $dark-accent, $dark-warn);

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

app.component.html

<div id="alternative-theme">
  <mat-sidenav-container class="app-container">
    <app-header></app-header>
    <router-outlet> </router-outlet>
    <app-footer></app-footer>
  </mat-sidenav-container>
</div>

app.component.css

#alternative-theme {
  display: block;
  height: 100%;
}

.app-container {
  height: inherit;
}

theme.service.ts

import { Injectable } from "@angular/core";
import { OverlayContainer } from "@angular/cdk/overlay";

@Injectable({
  providedIn: "root"
})
export class ThemeService {
  constructor(private overlayContainer: OverlayContainer) {
    this.overlayContainer = overlayContainer;
  }

  setDarkTheme() {
    document.getElementById("alternative-theme").classList.add("dark-theme");
    document.getElementById("footer-text").classList.remove("dark");
    this.overlayContainer.getContainerElement().classList.add("dark-theme");
  }

  setLightTheme() {
    document.getElementById("alternative-theme").classList.remove("dark-theme");
    document.getElementById("footer-text").classList.add("dark");
    this.overlayContainer.getContainerElement().classList.remove("dark-theme");
    document;
  }
}

Is this the best way to toggle between themes or is there a more robust way? I'm just starting with Angular and Material UI and if you have anything to add to the above snippets to make it better will be appreciated. Cheers.

the-ult commented 4 years ago

@nair-ayush

Just put the classes on your body or app:

<body class="mat-typography mat-app-background">
    <app-root></app-root>
  </body>

@see https://material.angular.io/guide/theming#using-a-pre-built-theme

Finally, if your app's content is not placed inside of a mat-sidenav-container element, you need to add the mat-app-background class to your wrapper element (for example the body). This ensures that the proper theme background is applied to your page.

tomasdev commented 4 years ago

Adding onto @intellix proposal:

It'd be backwards compatible to change the current mat-light-theme (and mat-dark-theme with the proper methods) implementations to call:

@function mat-light-theme(...) {
  // ...
  $result: $primary;
  @if map_get($primary, color) {
    $color-settings: map_get($primary, color);
    $primary: map_get($color-settings, primary);
    $accent: map_get($color-settings, accent);
    $warn: map_get($color-settings, warn);
    $foreground: map_get($color-settings, foreground);
    $background: map_get($color-settings, background);
    $result: map_merge($result, (color: _mat-create-light-color-config($primary, $accent, $warn, $foreground, $background)));
  }
  @return _mat-create-backwards-compatibility-theme(_mat-validate-theme($result));
}

@function _mat-create-light-color-config($primary, $accent, $warn: null, $foreground: $mat-light-theme-foreground, $background: $mat-light-theme-background) {
  @return (
    primary: $primary,
    accent: $accent,
    warn: if($warn != null, $warn, mat-palette($mat-red)),
    is-dark: false,
    foreground: $foreground,
    background: $background,
  );
}

This way, guarantees that people using the older stuff still works (since it defaults to the global variables) and yet people who want can use the cleaner method:

$theme: mat-light-theme((
  color: (
    primary: $primary,
    accent: $accent,
    warn: $warn,
    background: (
      app-bar: #fff,
    ),
  ),
));

Right now the equivalent of the above usage is:

$mat-light-theme-background: map_merge($mat-light-theme-background, (
  app-bar: #fff,
));

$theme: mat-light-theme((
  color: (
    primary: $primary,
    accent: $accent,
    warn: $warn,
  ),
));
diosney commented 4 years ago

Hopefully this gets added soon.

It is pretty annoying to being able to set primary, accent and warn palettes, and not being able to set the foreground and background ones in an easy and clean way too.

(Right now using the accepted answer at https://stackoverflow.com/questions/43919927/angular-material2-theming-how-to-set-app-background)

anschm commented 3 years ago

Can this please added soon. Thx.

rscircus commented 3 years ago

It took me days to find this issue from 2017... phew.

rscircus commented 3 years ago

OK, I managed to also apply the light/dark toggling to the whole app by putting everything in a container of class 'mat-app-background'.

rscircus commented 3 years ago

Like so:

image

michaelfaith commented 3 years ago

@fabienbranchel If you want to set the background colors, you likely want to customize the entire background and foreground palette by emulating the mat-light-theme or mat-dark-theme functions with your own replacement. Your replacement would include your own palettes instead of the mat-light-theme-foreground and background palettes.

I actually disagree with this assertion. I've been working through this myself recently, and you pretty much have to dig deeply into the theming api to figure out how to override the base background color. If we could pass some subset of the foreground and background theme object (just the things we care about overriding) into the define theme functions, and those partials are merged with what's being set by default, then that would seem like the best of both worlds. I basically had to do a map.deep-merge, after the theme was defined to augment the background palette that was generated by default. I didn't care about overriding everything, just a handful of surface properties.

Neutrino-Sunset commented 3 years ago

Where is it even documented what the sass identifiers for the background and foreground colours are? I don't even want to customize these values, I'm just trying to work out how to apply the existing theme values of the neutral colors (plus lighter and darker variants) to a custom component, but the documentation on using a theme in a custom component has no information on this at all.

https://material.angular.io/guide/theming-your-components

michaelfaith commented 3 years ago

Where is it even documented what the sass identifiers for the background and foreground colours are? I don't even want to customize these values, I'm just trying to work out how to apply the existing theme values of the neutral colors (plus lighter and darker variants) to a custom component, but the documentation on using a theme in a custom component has no information on this at all.

https://material.angular.io/guide/theming-your-components

It isn't documented at all, as far as i know. I just had to dig through the code to figure it out: https://github.com/angular/components/blob/c649f7dfca3df2cd3a47365a2930718dab4a8a09/src/material/core/theming/_palette.scss#L694

Neutrino-Sunset commented 3 years ago

So is using these hardcoded variable names officially supported, or is that something that's likely to break my app in a future release?

mattiLeBlanc commented 3 years ago

I just want to change the 'text' colour from the 'foreground' map. You used to be able to do it like described here: https://newbedev.com/how-to-change-font-color-of-primary-palette-in-angular-material2 but now that is no longer possible.

Why can't we support something like:

$core-theme: mat.define-light-theme((
  color: (
    primary: $primary,
    accent: $accent,
    warn: $warn,
    foreground: (
      base:              black,
      divider:           $dark-dividers,
      dividers:          $dark-dividers,
      disabled:          $dark-disabled-text,
      disabled-button:   rgba(black, 0.26),
      disabled-text:     $dark-disabled-text,
      elevation:         black,
      hint-text:         $dark-disabled-text,
      secondary-text:    $dark-secondary-text,
      icon:              rgba(black, 0.54),
      icons:             rgba(black, 0.54),
      text:              red,
      // text:              rgba(black, 0.87),
      slider-min:        rgba(black, 0.87),
      slider-off:        rgba(black, 0.26),
      slider-off-active: rgba(black, 0.38),
    )
  )
));

so I can change the text colour to whatever I want. And yes, the main issue is the mat-drawer-container getting the colour from foreground.text. I don't really want to CSS hack it is I can do it in a nice way.

michaelfaith commented 3 years ago

Why can't we support something like:

$core-theme: mat.define-light-theme((
  color: (
    primary: $primary,
    accent: $accent,
    warn: $warn,
    foreground: (
      base:              black,
      divider:           $dark-dividers,
      dividers:          $dark-dividers,
      disabled:          $dark-disabled-text,
      disabled-button:   rgba(black, 0.26),
      disabled-text:     $dark-disabled-text,
      elevation:         black,
      hint-text:         $dark-disabled-text,
      secondary-text:    $dark-secondary-text,
      icon:              rgba(black, 0.54),
      icons:             rgba(black, 0.54),
      text:              red,
      // text:              rgba(black, 0.87),
      slider-min:        rgba(black, 0.87),
      slider-off:        rgba(black, 0.26),
      slider-off-active: rgba(black, 0.38),
    )
  )
));

Yep, passing in the foreground and background overrides, and the define-*-theme function merging those onto the default would be my preference too. The only way I've been able to do it, is use the define function to generate the theme object, and then override those props after the fact. It's hacky, and i'd much prefer a way to do it that's officially supported, but it works for now.

michaelfaith commented 3 years ago

This function (and the dark theme version) is what would likely need to change, to allow for those parameters, instead of only taking defaults.

https://github.com/angular/components/blob/c649f7dfca3df2cd3a47365a2930718dab4a8a09/src/material/core/theming/_theming.scss#L114-L123

Ideally it would start with the defaults and merge in whatever overrides are passed in. So that the entire map doesn't need to be defined.

lerabela commented 2 years ago

Until a fix is added. just bypass the create theme function in your main style file.

see solution: https://stackblitz.com/edit/angular-material-custom-background?file=theme.scss

dhutaryan commented 2 years ago

Don't work:

$custom-theme: mat.define-light-theme(
  (
    color: (
      primary: $custom-primary,
      accent: $custom-accent,
      warn: $custom-warn,
    ),
  )
);

$background: map-get($custom-theme, background);
$background: map-merge(
  $background,
  (
    app-bar: red,
    background: #ffffff,
  )
);

$custom-theme: map-merge(
  $custom-theme,
  (
    background: $background,
  )
);

It would be nice to have easy way to change background and foreground

MikaStark commented 2 years ago

I agree that providing a way to easily customizing foreground and background colors would be a blast. Until now, I use my own theme mixin that override the existing one (in order to stay compatible with Material). But I would prefer Material provide the way to do it properly by passing just foreground and background variables (just like the other colors) Anyway, if someone is interesting in my code, here it is :

src/app/core/theming/_palette.scss

@use "sass:map";

// Of course you can customize everything ;)

$dark-primary-text: rgba(#000939, 0.87);
$dark-secondary-text: rgba(#000939, 0.54);
$dark-disabled-text: rgba(#000939, 0.38);
$dark-dividers: rgba(#000939, 0.12);
$dark-focused: rgba(#000939, 0.12);
$light-primary-text: white;
$light-secondary-text: rgba(white, 0.7);
$light-disabled-text: rgba(white, 0.5);
$light-dividers: rgba(white, 0.12);
$light-focused: rgba(white, 0.12);

$grey-palette: (
  50: #f7f9ff,
  100: #f1f3fb,
  200: #e8eaf2,
  300: #d9dbe3,
  400: #b5b7bf,
  500: #96979f,
  600: #6d6f76,
  700: #5a5b62,
  800: #3b3d43,
  900: #1b1c22,
  contrast: (
    50: $dark-primary-text,
    100: $dark-primary-text,
    200: $dark-primary-text,
    300: $dark-primary-text,
    400: $dark-primary-text,
    500: $dark-primary-text,
    600: $light-primary-text,
    700: $light-primary-text,
    800: $light-primary-text,
    900: $light-primary-text,
  ),
);

$night-palette: (
  50: #e3ecff,
  100: #bed1e9,
  200: #9eb1ce,
  300: #7c92b2,
  400: #637c9e,
  500: #4a668b,
  600: #3c597a,
  700: #2d4664,
  800: #1e344e,
  900: #0b2137,
  contrast: (
    50: $dark-primary-text,
    100: $dark-primary-text,
    200: $dark-primary-text,
    300: $light-primary-text,
    400: $light-primary-text,
    500: $light-primary-text,
    600: $light-primary-text,
    700: $light-primary-text,
    800: $light-primary-text,
    900: $light-primary-text,
  ),
);

// Background palette for light themes.
$light-theme-background-palette: (
  status-bar: map.get($grey-palette, 300),
  app-bar: white,
  background: map.get($grey-palette, 50),
  hover: rgba(#243b53, 0.04),
  card: white,
  dialog: white,
  disabled-button: rgba(#243b53, 0.12),
  raised-button: white,
  focused-button: $dark-focused,
  selected-button: map.get($grey-palette, 300),
  selected-disabled-button: map.get($grey-palette, 400),
  disabled-button-toggle: map.get($grey-palette, 200),
  unselected-chip: map.get($grey-palette, 200),
  disabled-list-option: map.get($grey-palette, 200),
  tooltip: map.get($grey-palette, 700),
);

// Background palette for dark themes.
$dark-theme-background-palette: (
  status-bar: #0b2844,
  app-bar: map.get($night-palette, 900),
  background: #102a43,
  hover: rgba(white, 0.04),
  card: map.get($night-palette, 800),
  dialog: map.get($night-palette, 800),
  disabled-button: rgba(white, 0.12),
  raised-button: map.get($night-palette, 800),
  focused-button: $light-focused,
  selected-button: map.get($night-palette, 900),
  selected-disabled-button: map.get($night-palette, 800),
  disabled-button-toggle: #243b53,
  unselected-chip: map.get($night-palette, 700),
  disabled-list-option: #243b53,
  tooltip: map.get($night-palette, 700),
);

// Foreground palette for light themes.
$light-theme-foreground-palette: (
  base: #243b53,
  divider: $dark-dividers,
  dividers: $dark-dividers,
  disabled: $dark-disabled-text,
  disabled-button: rgba(#243b53, 0.26),
  disabled-text: $dark-disabled-text,
  elevation: #243b53,
  hint-text: $dark-disabled-text,
  secondary-text: $dark-secondary-text,
  icon: rgba(#243b53, 0.54),
  icons: rgba(#243b53, 0.54),
  text: rgba(#243b53, 0.87),
  slider-min: rgba(#243b53, 0.87),
  slider-off: rgba(#243b53, 0.26),
  slider-off-active: rgba(#243b53, 0.38),
);

// Foreground palette for dark themes.
$dark-theme-foreground-palette: (
  base: white,
  divider: $light-dividers,
  dividers: $light-dividers,
  disabled: $light-disabled-text,
  disabled-button: rgba(white, 0.3),
  disabled-text: $light-disabled-text,
  elevation: black,
  hint-text: $light-disabled-text,
  secondary-text: $light-secondary-text,
  icon: white,
  icons: white,
  text: white,
  slider-min: white,
  slider-off: rgba(white, 0.3),
  slider-off-active: rgba(white, 0.3),
);

src/app/core/theming/_theming.scss

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

@function define-light-theme($config) {
  $theme: mat.define-light-theme($config);
  $color: map.get($theme, color);
  $color: map.merge(
    $color,
    (
      background: palette.$light-theme-background-palette,
      foreground: palette.$light-theme-foreground-palette,
    )
  );
  @return map.merge(
    $theme,
    (
      color: $color,
    )
  );
}

@function define-dark-theme($config) {
  $theme: mat.define-dark-theme($config);
  $color: map.get($theme, color);
  $color: map.merge(
    $color,
    (
      background: palette.$dark-theme-background-palette,
      foreground: palette.$dark-theme-foreground-palette,
    )
  );
  @return map.merge(
    $theme,
    (
      color: $color,
    )
  );
}

core/theming/_index.scss

@forward "palette";
@forward "theming";

// Here you can forward your own themes located in core/themeing/themes
// @forward "themes/xxxx" as xxxx-*;
// ...

src/styles.scss

@use "@angular/material" as mat;
@use "app/core/theming" as app;
@use "sass:map";

@include mat.core();

$app-primary: mat.define-palette(mat.$indigo-palette);
$app-accent: mat.define-palette(mat.$pink-palette);

// Use your own "app" define-light-theme function instead of "mat" one.
$app-theme: app.define-light-theme(
  (
    color: (
      primary: $app-primary,
      accent: $app-accent,
    )
  )
);
arbiyanto commented 2 years ago

@MikaStark trying to work around with your example in material v13, but it doesn't change anything to the theme.

palette.scss

@use "sass:map";

// Of course you can customize everything ;)

$dark-primary-text: rgba(#000939, 0.87);
$dark-secondary-text: rgba(#000939, 0.54);
$dark-disabled-text: rgba(#000939, 0.38);
$dark-dividers: rgba(#000939, 0.12);
$dark-focused: rgba(#000939, 0.12);
$light-primary-text: white;
$light-secondary-text: rgba(white, 0.7);
$light-disabled-text: rgba(white, 0.5);
$light-dividers: rgba(white, 0.12);
$light-focused: rgba(white, 0.12);

$grey-palette: (
  50: #f8fafc,
  100: #f1f5f9,
  200: #e2e8f0,
  300: #cbd5e1,
  400: #94a3b8,
  500: #64748b,
  600: #475569,
  700: #334155,
  800: #1e293b,
  900: #0f172a,
  contrast: (
    50: $dark-primary-text,
    100: $dark-primary-text,
    200: $dark-primary-text,
    300: $dark-primary-text,
    400: $dark-primary-text,
    500: $dark-primary-text,
    600: $light-primary-text,
    700: $light-primary-text,
    800: $light-primary-text,
    900: $light-primary-text,
  ),
);

$night-palette: (
  50: #f8fafc,
  100: #f1f5f9,
  200: #e2e8f0,
  300: #cbd5e1,
  400: #94a3b8,
  500: #64748b,
  600: #475569,
  700: #334155,
  800: #1e293b,
  900: #0f172a,
  contrast: (
    50: $dark-primary-text,
    100: $dark-primary-text,
    200: $dark-primary-text,
    300: $light-primary-text,
    400: $light-primary-text,
    500: $light-primary-text,
    600: $light-primary-text,
    700: $light-primary-text,
    800: $light-primary-text,
    900: $light-primary-text,
  ),
);

// Background palette for light themes.
$light-theme-background-palette: (
  status-bar: map.get($grey-palette, 300),
  app-bar: white,
  background: map.get($grey-palette, 50),
  hover: rgba(#243b53, 0.04),
  card: white,
  dialog: white,
  disabled-button: rgba(#243b53, 0.12),
  raised-button: white,
  focused-button: $dark-focused,
  selected-button: map.get($grey-palette, 300),
  selected-disabled-button: map.get($grey-palette, 400),
  disabled-button-toggle: map.get($grey-palette, 200),
  unselected-chip: map.get($grey-palette, 200),
  disabled-list-option: map.get($grey-palette, 200),
  tooltip: map.get($grey-palette, 700),
);

// Background palette for dark themes.
$dark-theme-background-palette: (
  status-bar: #0b2844,
  app-bar: map.get($night-palette, 900),
  background: #102a43,
  hover: rgba(white, 0.04),
  card: map.get($night-palette, 800),
  dialog: map.get($night-palette, 800),
  disabled-button: rgba(white, 0.12),
  raised-button: map.get($night-palette, 800),
  focused-button: $light-focused,
  selected-button: map.get($night-palette, 900),
  selected-disabled-button: map.get($night-palette, 800),
  disabled-button-toggle: #243b53,
  unselected-chip: map.get($night-palette, 700),
  disabled-list-option: #243b53,
  tooltip: map.get($night-palette, 700),
);

// Foreground palette for light themes.
$light-theme-foreground-palette: (
  base: #243b53,
  divider: $dark-dividers,
  dividers: $dark-dividers,
  disabled: $dark-disabled-text,
  disabled-button: rgba(#243b53, 0.26),
  disabled-text: $dark-disabled-text,
  elevation: #243b53,
  hint-text: $dark-disabled-text,
  secondary-text: $dark-secondary-text,
  icon: rgba(#243b53, 0.54),
  icons: rgba(#243b53, 0.54),
  text: rgba(#243b53, 0.87),
  slider-min: rgba(#243b53, 0.87),
  slider-off: rgba(#243b53, 0.26),
  slider-off-active: rgba(#243b53, 0.38),
);

// Foreground palette for dark themes.
$dark-theme-foreground-palette: (
  base: white,
  divider: $light-dividers,
  dividers: $light-dividers,
  disabled: $light-disabled-text,
  disabled-button: rgba(white, 0.3),
  disabled-text: $light-disabled-text,
  elevation: black,
  hint-text: $light-disabled-text,
  secondary-text: $light-secondary-text,
  icon: white,
  icons: white,
  text: white,
  slider-min: white,
  slider-off: rgba(white, 0.3),
  slider-off-active: rgba(white, 0.3),
);

theming.scss

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

@function define-light-theme($primary, $accent: null) {
  $theme: mat.define-light-theme($primary, $accent);
  $color: map.get($theme, color);
  $color: map.merge(
    $color,
    (
      background: palette.$light-theme-background-palette,
      foreground: palette.$light-theme-foreground-palette,
    )
  );
  @return map.merge(
    $theme,
    (
      color: $color,
    )
  );
}

@function define-dark-theme($primary, $accent: null) {
  $theme: mat.define-dark-theme($primary, $accent);
  $color: map.get($theme, color);
  $color: map.merge(
    $color,
    (
      background: palette.$dark-theme-background-palette,
      foreground: palette.$dark-theme-foreground-palette,
    )
  );
  @return map.merge(
    $theme,
    (
      color: $color,
    )
  );
}

styles.scss

@use '@angular/material' as mat;
@use "globals/theming" as app;

@include mat.core($custom-typography);
// ... primary accent variables

$dark-theme: app.define-dark-theme($dark-primary, $dark-accent);
@include mat.core-theme($dark-theme);
@include mat.button-theme($dark-theme);
@include mat.expansion-theme($dark-theme);

And I didn't change any code other than the color palette gray and night. But the end result is the component button and the expansion panel color are still same. Is there anything I missed?

MikaStark commented 2 years ago

@arbiyanto that’s because you are using the old/deprecated way to declare a theme. You provide two arguments to your define theme function instead of providing one which should be a theme config.

$app-dark-theme: app.define-dark-theme(
  (
    color: (
      primary: $app-primary,
      accent: $app-accent,
    )
  )
);
arbiyanto commented 2 years ago

@MikaStark I see, thanks for the response! it's working now.

ftaffelt commented 2 years ago

to mostly reuse the original angular material helper i used this approach to set some colors:

// ex. set custom text and secondary text color to css custom properties variant
// add this after mat.define-light-theme or mat.define-dark-theme and before emitting any component-themes
$custom-theme: map.set($custom-theme, color, foreground, text, var(--text-color));
$custom-theme: map.set($custom-theme, color, foreground, secondary-text, var(--secondary-text-color));
ibrcic commented 2 years ago

One solution that I found works perfectly and is easy to understand and use is using map.deep-merge() to merge generated theme map with my own overrides. Here is an example of overriding default light theme background and text color:

$theme: mat.define-light-theme(...);

$material-theme-overrides: (
  'color': (
    'background': (
      'background': var(--background),
    ),
    'foreground': (
      'text': var(--text-primary),
    ),
  ),
);

$theme: map.deep-merge($theme, $material-theme-overrides);

map.deep-merge() works similarly to map.merge() except that nested map values are also recursively merged. To check which properties you can actually override, you can check the bottom of this file in source for material theming. https://github.com/angular/components/blob/main/src/material/core/theming/_palette.scss

Alessandroinfo commented 1 year ago

I still have this issue. Themed Angular Material with mat.define-light-theme and mat.all-component-themes but for the primary button raised the text color is black and not white.

derSoerrn95 commented 1 year ago

After days of digging, I finally found @MikaStark's reply. Thanks @MikaStark! At least it would be great if his answer would be mentioned in the official docs.

Alessandroinfo commented 1 year ago

The answer of @MikaStark don't work for and the primary color text it's still black.

MikaStark commented 1 year ago

@Alessandroinfo this is an known issue of MDC migration (cf. https://github.com/angular/components/issues/26056) that is not related to this issue. The solution I proposed is working.

Alessandroinfo commented 1 year ago

@Alessandroinfo this is an known issue of MDC migration (cf. https://github.com/angular/components/issues/26056) that is not related to this issue. The solution I proposed is working.

@MikaStark I tried that here but don't work.

MikaStark commented 1 year ago

@Alessandroinfo this is an known issue of MDC migration (cf. #26056) that is not related to this issue. The solution I proposed is working.

@MikaStark I tried that here but don't work.

According to your code, you don’t override anything and as I said in my previous post, there is a known issue about contrast colors and buttons. I’m afraid that you are out of this issue scope.

Alessandroinfo commented 1 year ago

@MikaStark i reverted the edit. I've modified the theme like your answer but after i cannot see any color in my material component. As a soon i can I'll edit again and let you see.

AlonsoK28 commented 7 months ago

One solution that I found works perfectly and is easy to understand and use is using map.deep-merge() to merge generated theme map with my own overrides. Here is an example of overriding default light theme background and text color:

$theme: mat.define-light-theme(...);

$material-theme-overrides: (
  'color': (
    'background': (
      'background': var(--background),
    ),
    'foreground': (
      'text': var(--text-primary),
    ),
  ),
);

$theme: map.deep-merge($theme, $material-theme-overrides);

map.deep-merge() works similarly to map.merge() except that nested map values are also recursively merged. To check which properties you can actually override, you can check the bottom of this file in source for material theming. https://github.com/angular/components/blob/main/src/material/core/theming/_palette.scss

using your approach, how we can change the color of a mat-form-field ?

BenLune commented 5 months ago

Thanks @ibrcic for your great idea, which works. It's quite surprising such a standard theming needs is not considered. When we create an app, we need to be able to apply a custom theme, for everything. I think it was protected to prevent people from doing bad things, but we should be able to override it if we need it and we know what we do.