Component Themes

    Component themes allow you to change the styles of specific component instances by overriding the globally defined theme.

    Overview

    Before we dig deep into how you can create component-level themes, let's take a few moments to talk about how Ignite UI for Angular approaches component theming. Because we want to be able to support older browsers, like IE11, we have two completely different approaches for theming components.

    • The first approach is to style component instances using CSS variables. By using CSS variables we gain the ability to create component themes without replicating their styles over and over again. Also, this approach allows us to modify the value of the CSS variables at runtime.
    • The second approach is to create a new set of CSS rules that overwrite any previously declared CSS rules for a specific component. This approach is pretty straight-forward, and it is the only way we can provide sensible theming support for older browser, albeit it is not ideal as it adds a lot of additional CSS rules to the generated CSS theme.

    We'll take a look at how these approaches work in practice, and how to use one instead of the other when generating component-level themes.

    Creating Themes

    There are several parts to a component theme:

    • The component theme function - A Sass function that normalizes the passed arguments and produces a theme to be consumed by a component mixin.
    • The CSS variable mixin - A Sass mixin that consumes a component theme and produces CSS variables used to style a particular component.
    • The component mixin - A Sass mixin that consumes a component theme and produces CSS rules used to style a particular component.

    Say you want to create a new global avatar theme that has a different background color to the one we set in the avatar's default theme. As mentioned in the overview section there are 2 general approaches to creating a component theme. There are even more ways you can organize and scope your component themes. The most straightforward way to do that is in the same file you defined your global theme.

    Defining an avatar theme:

    // Some place after @include theme(...);
    
    // Change the background of the avatar to purple.
    $avatar-purple-theme: avatar-theme(
      $background: purple,
    );
    
    // Pass the css-vars to the `css-vars` mixin
    @include css-vars($avatar-purple-theme);
    

    The above code produces CSS variables for the igx-avatar component. These new CSS variables overwrite the default avatar rules. Similarly, if you were to include css-vars mixin later down in the global scss file, the mixin will again overwrite any previously defined themes.

    For instance:

    // ...
    @include css-vars($avatar-purple-theme);
    
    // Later
    $avatar-royalblue-theme: avatar-theme(
      $background: royalblue,
    );
    
    @include css-vars($avatar-royalblue-theme);
    

    In the above code, the de facto global theme is now the $avatar-royalblue-theme as it overwrites any previously included css-vars mixins.

    This brings us to our next point.

    Scoping Themes

    As we saw in the previous example, when adding multiple themes targeting the same component at the same level, the last theme mixin takes precedence. This is due to the way the CSS cascade works. If you want to have two or more themes targeting the same type of component, you will have to scope them to a selector. For instance we can create multiple igx-avatar themes and scope them to specific CSS selectors we can later use in our component markup.

    // ...
    // CSS class selectors
    .avatar-royalblue {
      @include css-vars($avatar-royalblue-theme);
    }
    
    .avatar-purple {
      @include css-vars($avatar-purple-theme);
    }
    

    In a component template:

    <div class="avatar-royalblue">
      <igx-avatar initials="AZ"></igx-avatar>
    </div>
    
    <div class="avatar-purple">
      <igx-avatar icon="home"></igx-avatar>
    </div>
    

    View Encapsulation

    So far we've explored ways to create themes that are globally scoped, and are included in a single Sass file. However, this is not always desirable, and in some instances you will want the Sass file to be bound to a specific component. In those cases we have to take View Encapsulation, and specifically how it is emulated in Angular, into consideration.

    The Angular team has adopted 3 strategies for View Encapsulation - Emulated(default), ShadowDom, and None. To learn more about each of these strategies, take a look at the Angular Documentation. We will take a closer look at how to handle theming of Ignite UI for Angular components that are part of View Encapsulated parent components.

    What exactly does Emulated View Encapsulation mean, anyway? This type of View Encapsulation does not take advantage of the Shadow DOM specification, instead it employs a way to bind styles for a component and its children by using a unique attribute identifier applied on the host element.

    Let's take a look at an example using CSS variables. Let's create an avatar theme that is bound to specific parent component.

    Here's our simple component:

    import { Component, Input } from "@angular/core";
    
    @Component({
      selector: "app-avatar",
      styleUrls: ["./app-avatar.component.scss"],
      template: `<igx-avatar [initials]="initials"></igx-avatar>`,
    })
    export class AvatarComponent extends Component {
      @Input() public initials = "AZ";
    }
    

    And this is what our Sass stylesheet looks like:

    // app-avatar.component.scss
    
    // Import the theming module
    @use "igniteui-angular/theming" as *;
    
    // !IMPORTANT: Prior to Ignite UI for Angular version 13 use:
    // @import '~igniteui-angular/lib/core/styles/themes/index';
    
    $avatar-royalblue-theme: avatar-theme(
      $background: royalblue,
    );
    
    :host {
      @include css-vars($avatar-royalblue-theme);
    }
    

    When using CSS variables, we don't have to use the ::ng-deep pseudo-selector. With the code above we've created CSS variables for the igx-avatar, which will always have royalblue as its background color. The theme for our custom avatar will not 'leak' into other igx-avatar component instances, thus staying encapsulated within our custom app-avatar component.

    The above instance could also be achieved without using any Sass. All we need to do is to set the value of --igx-avatar-background CSS variable to the desired color:

    /* app-avatar.component.css */
    :host {
      --igx-avatar-background: royalblue;
    }
    

    API Overview

    Additional Resources

    Learn how to configure a global theme:

    Our community is active and always welcoming to new ideas.