Customizing Mat Horizontal Stepper Icons with Unique Background Colors in Angular Material

I'm having trouble customizing the colors of the icons

In my mat-horizontal-stepper, I have five mat-steps (Part A, Part B ... Part E), each needing a different color based on certain business rules.

While I can change the color for all steps or the "selected" step, I can't seem to figure out how to dynamically change the icon background color for each individual part. I am using Angular v7.

The following CSS snippet sets the third mat-step icon's background color to green. It works, but I need to know how to change this color dynamically at run-time from the component (typescript).

::ng-deep .mat-step-header:nth-of-type(3) .mat-step-icon {
    background-color: green!important; 
}

I also attempted to use [ngClass], but it is ignored when added as a mat-step attribute. It only applies if I include it within the step label, which doesn't meet the requirement of changing the icon's background color instead of the labels.

Expected outcome: Being able to assign different colors to each step based on completion level, such as yellow, red, green, and black.

Current issue: Unable to dynamically adjust icon colors based on component variable settings

Answer №1

This particular query revolves around the management of CSS variables through TypeScript - I received assistance from this specific post.

  • CSS: We linked three variables to three icons that required coloring.
  • HTML: Two divs, firstClass and secondClass, were established alongside the <body> tag for assigning uniquely named variables such as color1, color2, and color3.
  • Given our usage of 'mat-table,' using [ngStyle] or [ngClass] isn't viable since the material components are generated at runtime. Thus, we exclusively manipulate them in the AfterViewInit event where values are allocated to the two divs and the <body> tag.

Important CSS:

::ng-deep .mat-step-header:nth-of-type(1) .mat-step-icon {
    background-color: var(--my-var1);
 } 

::ng-deep .mat-step-header:nth-of-type(2) .mat-step-icon {
    background-color: var(--my-var2);
 } 

::ng-deep .mat-step-header:nth-of-type(3) .mat-step-icon {
    background-color: var(--my-var3);
 } 

Important HTML:

<div class='firstClass'>
    <div class='secondClass'>
        <mat-horizontal-stepper labelPosition="bottom" #stepper>
            <mat-step [stepControl]="firstFormGroup">
                <form [formGroup]="firstFormGroup">
                    <ng-template matStepLabel>Fill out your name</ng-template>
                    <mat-form-field>
                        <input matInput placeholder="Last name, First name" formControlName="firstCtrl" required>
            </mat-form-field>
            <div>
                <button mat-button matStepperNext>Next</button>
            </div>
        </form>
    </mat-step>
    <mat-step [stepControl]="secondFormGroup" optional>
        <form [formGroup]="secondFormGroup">
            <ng-template matStepLabel>Fill out your address</ng-template>
            <mat-form-field>
                <input matInput placeholder="Address" formControlName="secondCtrl" required>
            </mat-form-field>
            <div>
                <button mat-button matStepperPrevious>Back</button>
                <button mat-button matStepperNext>Next</button>
            </div>
        </form>
    </mat-step>
    <mat-step>
        <ng-template matStepLabel>Done</ng-template>
        You are now done.
        <div>
            <button mat-button matStepperPrevious>Back</button>
            <button mat-button (click)="stepper.reset()">Reset</button>
        </div>
    </mat-step>
  </mat-horizontal-stepper>
  <div>
<div>

Important TS:

import {Component, OnInit, AfterViewInit} from '@angular/core';
import {FormBuilder, FormGroup, Validators} from '@angular/forms';

@Component({
  selector: 'stepper-label-position-bottom-example',
  templateUrl: 'stepper-label-position-bottom-example.html',
  styleUrls: ['stepper-label-position-bottom-example.css'],
})
export class StepperLabelPositionBottomExample implements OnInit, AfterViewInit {
  firstFormGroup: FormGroup;
  secondFormGroup: FormGroup;
  color1:string = 'green';
  color2:string = 'yellow';
  color3:string = 'red';

  constructor(private _formBuilder: FormBuilder) {}

  ngOnInit() {
    this.firstFormGroup = this._formBuilder.group({
      firstCtrl: ['', Validators.required]
    });
    this.secondFormGroup = this._formBuilder.group({
      secondCtrl: ['', Validators.required]
    });
  }

  ngAfterViewInit(){
    document.querySelector("body").style.cssText = "--my-var1: "+this.color1;
    (<HTMLElement>document.querySelector('.secondClass')).style.cssText = "--my-var2: "+this.color2;
    (<HTMLElement>document.querySelector('.firstClass')).style.cssText = "--my-var3: "+this.color3;
  }

}

Check out the full live example on StackBlitz here.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Accessing information independent of Observable data in TypeScript

When attempting to send an HttpRequest in Typescript, I encountered an issue where the received data could not be stored outside of the subscribe function. Despite successfully saving the data within the subscribe block and being able to access it there, ...

Is there a way to efficiently access checkboxes by their IDs and toggle classes without the need for redundant classes and functions?

In my current project, I have set up functionality to toggle classes on a table for hiding specific columns. This is determined by checkboxes selected by the user above the table, each checkbox having its own unique ID like "product_1", "product_2", and so ...

Pause the event listener temporarily and reattach it after specific actions have been completed

I am currently working on a React app that includes a scrollable div. Here is an example: <main id="main" onScroll={this.handleScroll}> My question is, how can I temporarily remove the onScroll event listener from the main element and then reattach ...

Is it possible to eliminate the border of an HTML element when clicked, while still keeping the border intact when the element is in

I am currently developing a project with an emphasis on Web accessibility. Snippet of Code: function removeBorder(){ li=document.getElementById("link"); li.classList.add(".remove") } body{ background:#dddddd; } p:focus{ border:1px solid red; } li{ ...

Picture inside text area covering drop-down list

After making some adjustments to Bootstrap using a custom -theme.css file, I successfully altered the appearance of the dropdown menu. By removing the borders from the navbar and wrapping a header around it set to be fixed on top, everything seemed to be w ...

What is the process for spinning an image?

Is there a way to rotate an image around its center? I am looking for a solution where the image rotates continuously when clicked, but stops if an ajax call is unsuccessful. Please assist me in finding a resolution. ...

Managing business logic in an observable callback in Angular with TypeScript - what's the best approach?

Attempting to fetch data and perform a task upon success using an Angular HttpClient call has led me to the following scenario: return this.http.post('api/my-route', model).subscribe( data => ( this.data = data; ...

Troubleshooting HTML Label Problems

I am facing an issue with my custom labels. .label-ras{ padding:3px 10px; line-height:15px; color:#fff; font-weight:400; border-radius:5px; font-size:75%; } .label-primar{background-color:#5c4ac7} <span style="background- ...

Transforming a current angular 2 project to incorporate angular CLI

I was working on a project which wasn't set up using the 'ng new' command, but rather I followed the steps outlined in the quickstart guide. However, whenever I try to use an angular CLI command like 'ng generate', I keep getting t ...

Incorporating an external SVG file into an Angular project and enhancing a particular SVG element within the SVG with an Angular Material Tooltip, all from a TypeScript file

Parts of the angular code that are specific |SVG File| <svg version="1.0" xmlns="http://www.w3.org/2000/svg" width="950" height="450" viewBox="0 0 1280.000000 1119.000000" preserveAspectRatio= ...

Tips for creating a more condensed materialized table with form elements

Currently, I am working on a timesheet table using Materialize CSS with form elements in cells. However, I find the height of the table rows to be too large for my liking. Is there any way to make the table more compact? If this is a limitation of Materi ...

Using the flex:1 property does not automatically make my elements the same size and cover the entire height of the container

I have 2 containers and I want the elements in each container to fill the entire container. My goal is to make one container appear larger than the other. https://i.stack.imgur.com/73yoR.jpg Even though I am using the flex: 1 property, it does not seem t ...

Traversing Abstract Syntax Trees Recursively using TypeScript

Currently in the process of developing a parser that generates an AST and then traversing it through different passes. The simplified AST structure is as follows: type LiteralExpr = { readonly kind: 'literal', readonly value: number, }; type ...

Underscore.js is failing to accurately filter out duplicates with _uniq

Currently, I am integrating underscorejs into my angular project to eliminate duplicate objects in an array. However, I have encountered an issue where only two string arrays are being kept at a time in biddingGroup. When someone else places a bid that is ...

Thumbnails failing to line up in a continuous row

Having an issue creating a row with 3 thumbnails as they are not aligning in a single row, instead each thumbnail is going into a different row. echo "<table>"; echo "<tr>"; echo "</tr>"; while($r ...

Is it possible to utilize the $ symbol within the ngOnInit or constructor functions?

I recently encountered an issue while trying to use the dollar sign ($) in my constructor function, specifically within ngOnInit() and translate.instant. Here is a snippet of the code that caused the problem: declare var $: any; { var SelectedDevice = ...

Ways to loop through a collection of indexed elements

I am working with an array of indexed objects and my goal is to iterate through it in order to transform it into a new flattened array. Here is the initial array of objects: "attentionSchedules": [ { "room": "1", ...

Is there a way for TS-Node to utilize type definitions from the `vite-env.d.ts` file?

I am utilizing Mocha/Chai with TS-Node to conduct unit tests on a React/TypeScript application developed with Vite. While most tests are running smoothly, I am encountering difficulties with tests that require access to type definitions from vite-env.d.ts ...

Ways to invoke a function in Angular2 when the Boolean condition is met

Within my component class, I have implemented a popup function along with a Boolean flag that returns true or false based on specified conditions. In the template class, I want the popup function to be triggered when the flag becomes true, displaying a pop ...

Error message: While running in JEST, the airtable code encountered a TypeError stating that it cannot read the 'bind' property of an

Encountered an error while running my Jest tests where there was an issue with importing Airtable TypeError: Cannot read property 'bind' of undefined > 1 | import AirtableAPI from 'airtable' | ^ at Object.&l ...