Search code examples
javascripthtmlangularsass

Applying styles to innerHTML in Angular


I have an Angular component named ExternalHtmlComponent responsible for rendering HTML content fetched from the backend. The HTML content is dynamically inserted into a element using the [innerHTML] property binding. To style the dynamically inserted HTML content, I've defined a mixin called external-html in the components/external-html.scss file. However these styles are not applied to tags.

How can I ensure that all styles defined in external-html.scss are correctly applied to the corresponding HTML elements within the dynamically inserted html ?

components/external/external_html.component.ts

import {Component, ViewEncapsulation, Input, OnInit} from '@angular/core';

@Component({
  selector: 'component-external-html',
  template: '<div [innerHTML]="html"> </div>',
  styleUrls: ['./external-html.component.scss'],
  encapsulation: ViewEncapsulation.None
})
export class ExternalHtmlComponent {

  @Input() html: string;

  constructor() { }

}

components/external/external_html.component.scss

@import "components/external-html";

:host {
  @include external-html;
}

components/external-html.scss

@mixin external-html {
    font: var(--font-body);
    color: var(--color-text); // only these changes are applied, when inspected.
    // if I add background color here, <a> tags gets it.

    h1 {
        font: var(--font-subtitle);
    }
    
    h2 {
        font: var(--font-label-bold);
        text-transform: uppercase;
        color: var(--color-secondary);
    }
    
    h3 {
        font: var(--font-emphasis);
    }
    
    b, strong {
        font: var(--font-body-semibold);
        background-color: red;
    }
    
    a {
        font: var(--font-body-semibold);
        color: var(--color-primary);
        text-decoration: underline;
    }
    
    blockquote {
        display: inline-flex;
        justify-content: center;
        align-items: center;
        padding: var(--spacing-2);
        border-radius: var(--border-radius-2);
        background-color: var(--color-primary-05);
    }
}

Here is the usage of it:

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-external-html-example',
  template: '<component-external-html [innerHTML]="exampleHtmlContent"></component-external-html>',
})
export class ExternalHtmlExampleComponent implements OnInit {

  constructor() { }

  ngOnInit(): void {
  }

  public exampleHtmlContent: string = `
  <h1>This is a Heading 1</h1>
  <h2>This is a Heading 2</h2>
  <h3>This is a Heading 3</h3>
  <p>This is a paragraph with <b>bold</b> text.</p>
  <a href="#">This is a link</a>
  <ul>
    <li>Unordered list item 1</li>
    <li>Unordered list item 2</li>
  </ul>
  <ol>
    <li>Ordered list item 1</li>
    <li>Ordered list item 2</li>
  </ol>
  <blockquote>
    This is a blockquote with background color, padding, and rounded corners.
  </blockquote>
`;

}


Solution

  • I can see a problem, you need to pass [html] instead of [innerHTML] in the below line!

    ...
    @Component({
      selector: 'app-external-html-example',
      template: '<component-external-html [html]="exampleHtmlContent"></component-external-html>',
    })
    ...
    

    [innerHTML] mostly destroyed the component so the styles did not get applied is my theory!


    The content rendered inside the innerHTML is not technically part of the component so we need to put the CSS inside global-styles.scss then it will get applied to the innerHTML elements, there is no need for ViewEncapsulation.None!

    /* Add application styles & imports to this file! */
    
    @import './app/test/components/external-html';
    
    component-external-html {
      @include external-html;
    }
    

    Stackblitz Demo