Css style

Bind CSS styles to events in Angular apps

Angular allows you to conditionally set classes and styles through the ngClass and ngStyle directives respectively. Overall these work very well. However, there are cases where they cannot be used, i.e. for:

  • the dynamic styling of elements using TypeScript variables that are only known at runtime, or
  • assigning styles to pseudo-classes such as focus and hover.

Techniques will be demonstrated using an application which passes theme colors to a component via @Grab settings. These will be used to set the context, floatand focus border colors.

The demo app

Here is a screenshot of the demo application that shows the three colors that can be set dynamically via input fields:

Each color is shown in a square above the form for reference. Below the form, you will find an SVG of the famous Twitter logo. We can see the selected hover color when the cursor is placed over the image:

CSS Overview Tutorial

Tabbing the image changes the border to the color of the selected focus border color:

CSS border color

Of the three colors, only the background can be set using an Angular directive; the other two require a different solution, like the ones below.

Technique #1: CSS Variables

You may be familiar with the Less and Sass variables which are compiled to pure CSS before use. Now there are “pure” CSS variables. These are defined by prefixing a double dash (–) before the variable name. Then, to access the value of a CSS variable, we would pass it to the var() a function. Our application declares three of these variables – one for each color definition:

These are used to define the three preview squares in the Application component.

$backgroundColor: var(--background-color);
$hoverColor: var(--hover-color);
$focusBorderColor: var(--focus-border-color);

These variables are applied to CSS rules as follows:

.background {
  background-color: $backgroundColor;
}

.hover-background {
  background-color: $hoverColor;
}

.focus-border-background {
  background-color: $focusBorderColor;
}

If the var() the function looks familiar, that’s by design. It is named after the JavaScript (JS) variable declaration keyword. This is because we can reference (and modify!) CSS variables in our JS code, or, in the case of Angular apps, in the TypeScript .ts component files. Here is the function that assigns three JS variables to the above CSS variables we declared earlier:

public setColors(background: string, hover: string, focus: string) {
  const docStyle = document.documentElement.style;
  docStyle.setProperty('--background-color', background);
  docStyle.setProperty('--hover-color', hover);
  docStyle.setProperty('--focus-border-color', focus);
}

the setColors() function is bound to the click event of the APPLY button. Each input field ngModel variable is passed as a function parameter:

>

Although not part of the demo, it should be noted that CSS variables are also applicable to pseudo-classes since the stylesheet has access to the variables:

.news-image: hover {
  background-color: $hoverColor;
}

Technique #2: Define styles programmatically

All HTML elements expose a style property, which allows us to set just about any style directly, without referring to the style sheet. In the flow component, there are two similar methods for setting SVG element styles: one for the background color and another for the focus border:

public setHoverColor(event: MouseEvent) {
  const newsImage: HTMLDivElement = event.target;

  if (event.type === 'mouseenter') {
    newsImage.style.backgroundColor = this.hoverBackgroundColor;
  } else if (event.type === 'mouseleave') {
    newsImage.style.backgroundColor = this.backgroundColor;
  }
}
public setFocusStyle(event: FocusEvent) {
  const newsImage: HTMLDivElement = event.target;

  if (event.type === 'focus') {
    newsImage.style.outline = "2px solid " + this.focusBorderColor;
  } else if (event.type === 'blur') {
    newsImage.style.outline = "none";
  }
}

The above class member variables can be set via @Grab settings; otherwise, they keep their default values:

export class FeedComponent {
  @Input('background-color') 
  backgroundColor: string = 'rgb(82, 172, 240)';
  @Input('hover-background-color') 
  hoverBackgroundColor="cyan";
  @Input('focus-border-color') 
  focusBorderColor="#CCCCCC";
  
}

Each event type check in both functions corresponds to a related event on the news-image element. Either way, the $event is passed to the function to get the type and target of the event:

// ...

Passing Colors to Stream Component

In order to trigger color updates on the APPLY button click event (as opposed to immediately), three additional variables are used. These are defined along with the CSS variables in setColors():

backgroundColorInput: string = 'rgb(82, 172, 240)';
hoverColorInput: string = 'blue';
focusBorderColorInput: string = 'darkgray';
  
public setColors(background: string, hover: string, focus: string) {
  const docStyle = document.documentElement.style;
  docStyle.setProperty('--background-color', background);
  this.backgroundColorInput = background;
  docStyle.setProperty('--hover-color', hover);
  this.hoverColorInput = hover;
  docStyle.setProperty('--focus-border-color', focus);
  this.focusBorderColorInput = focus;
}

This way, the flow component’s input variables are bound to the new variables and not to those in the text fields. ngModels:



Don’t forget to watch the demo on stack blitz.

Read more CSS and web design tutorials.

Conclusion

In this tutorial, we learned two techniques for dynamically styling elements where the ngClass and ngStyle directives will not work. In the next article, we’ll learn how to apply CSS variables to specific elements.