mic_test
mic_test

Reputation: 161

It is possible change angular material mat-slide-toggle icon?

I'm using angular material version 9.2.4.

I want to overwrite the toggle icon to font awesome icon and I found some example is using css code background-image to overwrite it, but it is possible to use the font-awesome to change the toggle icon?
This is what I want to customize the icon toggle.
enter image description here

Upvotes: 9

Views: 11301

Answers (5)

Jonathan Moy
Jonathan Moy

Reputation: 438

In Angular 15 :

you can modify the icon class like this :

::ng-deep .mdc-switch__icons{
  display:none!important;
}

this example disable the icons. I spent too long time to find this, I hope it helps some people!

Upvotes: 3

Ultor
Ultor

Reputation: 89

You can try this:

Angular >= 15 with SVG

Let's say you have simple slide toggle with custom class in HTML:

<mat-slide-toggle class="icon-slide-toggle"></mat-slide-toggle>

And now you edit path of SVGs in SCSS:

$sun-path: 'm5.64 17l-.71.71a1 1 0 0 0 0 1.41a1 1 0 0 0 1.41 0l.71-.71A1 1 0 0 0 5.64 17ZM5 12a1 1 0 0 0-1-1H3a1 1 0 0 0 0 2h1a1 1 0 0 0 1-1Zm7-7a1 1 0 0 0 1-1V3a1 1 0 0 0-2 0v1a1 1 0 0 0 1 1ZM5.64 7.05a1 1 0 0 0 .7.29a1 1 0 0 0 .71-.29a1 1 0 0 0 0-1.41l-.71-.71a1 1 0 0 0-1.41 1.41Zm12 .29a1 1 0 0 0 .7-.29l.71-.71a1 1 0 1 0-1.41-1.41l-.64.71a1 1 0 0 0 0 1.41a1 1 0 0 0 .66.29ZM21 11h-1a1 1 0 0 0 0 2h1a1 1 0 0 0 0-2Zm-9 8a1 1 0 0 0-1 1v1a1 1 0 0 0 2 0v-1a1 1 0 0 0-1-1Zm6.36-2A1 1 0 0 0 17 18.36l.71.71a1 1 0 0 0 1.41 0a1 1 0 0 0 0-1.41ZM12 6.5a5.5 5.5 0 1 0 5.5 5.5A5.51 5.51 0 0 0 12 6.5Zm0 9a3.5 3.5 0 1 1 3.5-3.5a3.5 3.5 0 0 1-3.5 3.5Z';
$moon-path: 'M21.64 13a1 1 0 0 0-1.05-.14a8.05 8.05 0 0 1-3.37.73a8.15 8.15 0 0 1-8.14-8.1a8.59 8.59 0 0 1 .25-2A1 1 0 0 0 8 2.36a10.14 10.14 0 1 0 14 11.69a1 1 0 0 0-.36-1.05Zm-9.5 6.69A8.14 8.14 0 0 1 7.08 5.22v.27a10.15 10.15 0 0 0 10.14 10.14a9.79 9.79 0 0 0 2.1-.22a8.11 8.11 0 0 1-7.18 4.32Z';

::ng-deep .icon-slide-toggle .mdc-switch__icon {
  transform: scale(0.8); // This is optional for a better icon fit

  // Toggle off
  &--off > path {
    d: path($sun-path);
  }
  
  // Toggle on
  &--on > path {
    d: path($moon-path);
  }
}

Remember to provide proper path for SVGs since their viewBoxes are "0 0 24 24". I recommend this page where you can search for icons you are interested in.

Angular < 15

First, import font awesome either by direct import in your css file or by adding link in head

Secondly, override styles for mat-slide-toggle. I'm using ::ng-deep to make sure it will apply:

::ng-deep .mat-slide-toggle .mat-slide-toggle-thumb:before { 
  content: "\f185"; // sun icon
  font-family: "Font Awesome 5 Free";
  font-style: normal;
  font-weight: normal;
  font-size: 20px;
}

::ng-deep .mat-slide-toggle.mat-checked:not(.mat-disabled) .mat-slide-toggle-thumb:before { 
  content: "\f186"; // moon icon
  font-family: "Font Awesome 5 Free";
  font-style: normal;
  font-weight: normal;
  font-size: 20px;
}

// Disable thumb bg color so the icon is fully visible
::ng-deep .mat-slide-toggle.mat-checked .mat-slide-toggle-thumb {
  background-color: transparent !important;
}

::ng-deep .mat-slide-toggle-thumb {
  background-color: transparent !important;
}

I hope it helps ^^

Upvotes: 3

Joosep Parts
Joosep Parts

Reputation: 6235

This should be doable with some DOM manipulation. This works for Material 15 at the time of writing.

Material >= 15 (using SVG)

enter image description here

Material 15 (with MDC-based components) now features mat-slide-toggle with icons (SVG paths in this case). Though it's not possible to swap out the switch icon - instead, we could target them and change the path.d attribute.

  1. I took icons for dark/light mode from material icons and downloaded it as SVG. https://fonts.google.com/icons?icon.query=dark+mode

  2. I scaled them down by 50% using an online SVG editor: https://aydos.com/svgedit/ Icon needed to be scaled down to fit the switch.

  3. Using @ViewChild to find and query the right SVG targets and replace their attributes. I replaced the default attribute d on path with the scaled-down version. We need to read the element as ElementRef using { read: ElementRef } to access nativeElement.

Though using querySelector is not optimal - perhaps there are better ways.

html:

<mat-slide-toggle #darkModeSwitch></mat-slide-toggle>

ts:

@Component({
  selector: 'slide-toggle-overview-example',
  templateUrl: 'slide-toggle-overview-example.html',
})
export class SlideToggleOverviewExample implements AfterViewInit {

  @ViewChild('darkModeSwitch', { read: ElementRef }) element: ElementRef | undefined;


  sun = 'M12 15.5q1.45 0 2.475-1.025Q15.5 13.45 15.5 12q0-1.45-1.025-2.475Q13.45 8.5 12 8.5q-1.45 0-2.475 1.025Q8.5 10.55 8.5 12q0 1.45 1.025 2.475Q10.55 15.5 12 15.5Zm0 1.5q-2.075 0-3.537-1.463T7 12q0-2.075 1.463-3.537T12 7q2.075 0 3.537 1.463T17 12q0 2.075-1.463 3.537T12 17ZM1.75 12.75q-.325 0-.538-.213Q1 12.325 1 12q0-.325.212-.537Q1.425 11.25 1.75 11.25h2.5q.325 0 .537.213Q5 11.675 5 12q0 .325-.213.537-.213.213-.537.213Zm18 0q-.325 0-.538-.213Q19 12.325 19 12q0-.325.212-.537.212-.213.538-.213h2.5q.325 0 .538.213Q23 11.675 23 12q0 .325-.212.537-.212.213-.538.213ZM12 5q-.325 0-.537-.213Q11.25 4.575 11.25 4.25v-2.5q0-.325.213-.538Q11.675 1 12 1q.325 0 .537.212 .213.212 .213.538v2.5q0 .325-.213.537Q12.325 5 12 5Zm0 18q-.325 0-.537-.212-.213-.212-.213-.538v-2.5q0-.325.213-.538Q11.675 19 12 19q.325 0 .537.212 .213.212 .213.538v2.5q0 .325-.213.538Q12.325 23 12 23ZM6 7.05l-1.425-1.4q-.225-.225-.213-.537.013-.312.213-.537.225-.225.537-.225t.537.225L7.05 6q.2.225 .2.525 0 .3-.2.5-.2.225-.513.225-.312 0-.537-.2Zm12.35 12.375L16.95 18q-.2-.225-.2-.538t.225-.512q.2-.225.5-.225t.525.225l1.425 1.4q.225.225 .212.538-.012.313-.212.538-.225.225-.538.225t-.538-.225ZM16.95 7.05q-.225-.225-.225-.525 0-.3.225-.525l1.4-1.425q.225-.225.538-.213.313 .013.538 .213.225 .225.225 .537t-.225.537L18 7.05q-.2.2-.512.2-.312 0-.538-.2ZM4.575 19.425q-.225-.225-.225-.538t.225-.538L6 16.95q.225-.225.525-.225.3 0 .525.225 .225.225 .225.525 0 .3-.225.525l-1.4 1.425q-.225.225-.537.212-.312-.012-.537-.212ZM12 12Z'
  moon ='M12 21q-3.75 0-6.375-2.625T3 12q0-3.75 2.625-6.375T12 3q.2 0 .425.013 .225.013 .575.038-.9.8-1.4 1.975-.5 1.175-.5 2.475 0 2.25 1.575 3.825Q14.25 12.9 16.5 12.9q1.3 0 2.475-.463T20.95 11.15q.025.3 .038.488Q21 11.825 21 12q0 3.75-2.625 6.375T12 21Zm0-1.5q2.725 0 4.75-1.687t2.525-3.963q-.625.275-1.337.412Q17.225 14.4 16.5 14.4q-2.875 0-4.887-2.013T9.6 7.5q0-.6.125-1.287.125-.687.45-1.562-2.45.675-4.062 2.738Q4.5 9.45 4.5 12q0 3.125 2.188 5.313T12 19.5Zm-.1-7.425Z'

  ngAfterViewInit() {
    if (this.element){
      this.element.nativeElement.querySelector('.mdc-switch__icon--on').firstChild.setAttribute('d', this.moon);
      this.element.nativeElement.querySelector('.mdc-switch__icon--off').firstChild.setAttribute('d', this.sun);
    }
  }
}

Working example: https://stackblitz.com/edit/angular-3fkfgv?file=src%2Fapp%2Fslide-toggle-overview-example.ts


Material < 15 (using mat-icon)

enter image description here

html

<mat-slide-toggle
  #darkModeSwitch
  (change)="changeTheme()"
  [checked]="checked"
  [disabled]="disabled">
</mat-slide-toggle>

ts

import {AfterViewInit, Component, ElementRef, Renderer2, ViewChild} from '@angular/core';

@Component({
  selector: 'slide-toggle-overview-example',
  templateUrl: 'slide-toggle-overview-example.html',
  styleUrls: ['slide-toggle-overview-example.css'],
})
export class SlideToggleOverviewExample implements AfterViewInit {
  constructor(private renderer: Renderer2) {}

  @ViewChild('darkModeSwitch', { read: ElementRef }) element: ElementRef | undefined;

  checked = false;
  disabled = false;

  ngAfterViewInit() {
    this.setIcon();
  }

  setIcon() {
    if (this.element) {
      const targetSpan: HTMLElement = this.element.nativeElement.querySelector('.mat-slide-toggle-thumb');
      while (targetSpan.firstChild) {
        targetSpan.firstChild.remove();
      }
      const elem = this.renderer.createElement('mat-icon');
      const icon = this.checked ? 'dark_mode' : 'light_mode';
      elem.setAttribute('class', 'mat-icon notranslate material-icons mat-icon-no-color light-mode-switch-icon');
      elem.textContent = icon
      targetSpan.appendChild(elem);
    }
  }

  changeTheme() {
    this.checked = !this.checked;
    console.log('I am now ', this.checked);
    this.setIcon();
  }
}

Example: https://stackblitz.com/edit/angular-nnj29e?file=app%2Fslide-toggle-overview-example.ts

Upvotes: 13

Cagri Tacyildiz
Cagri Tacyildiz

Reputation: 17610

Demo After import fontawesome in project do it in style.css

.mat-slide-toggle.mat-checked:not(.mat-disabled) .mat-slide-toggle-thumb:before { 
    content: "\f00c";
    font: normal normal normal 14px/1 FontAwesome;
}

Upvotes: 5

onik
onik

Reputation: 1631

Unfortunately, mostly it is too hard, to override look and layout in Angular Material, even changing the styles is sometimes harsh. No currently there is no way to change the icon officially

Upvotes: 0

Related Questions