Search code examples
sassweb-componentstenciljs

Can StencilJS component use external theming?


I'm trying out StencilJS for creating reusable web components for multiple projects that I'm working on. But I'm having a hard time to inherit the color themes from my main applications to, let's say, my Stencil button component. Example: I want to use different primary and secondary coloring for my applications that applies on my Stencil components like a primary colored button. But how do I manage to do so? I'm using sass styling and have the primary variable locally set in my Stencil project with my theme. But I don't know how to import external sass/css files after compilation.

<my-button color="primary">This is a primary button</my-button>

Solution

  • At the bottom of the Styling docs there is a section about how to use CSS variables:

    In this example we have defined a CSS Variable called --app-primary-color that is set to the color #488aff. The :root selector in this example is a CSS pseudo selector that defines the variable on the root element of your project (usually <html>) so that the variable can be used across your app.

    So if you have a button component like this:

    @Component({ tag: 'my-button', styleUrl: 'button.css' })
    export class Button {
      render() {
        return <div class="button"><slot /></div>;
      }
    }
    

    And the following button.css for it:

    .button {
      background: var(--primary-color, tomato);
      color: var(--light-color, white);
    
      display: block;
      padding: 1em 2em;
      border-radius: 0.2em;
      font-family: sans-serif;
      text-align: center;
      text-transform: uppercase;
    }
    

    Then you can overwrite all button colors by setting the variable somewhere in your CSS:

    :root {
      --primary-color: mediumseagreen;
    }
    

    CSS Variables can also be set using Javascript, and they are even polyfilled by Stencil for older browsers.

    JSFiddle example: http://jsfiddle.net/5fv9r6e1/


    Btw, in your component decorator you can also set shadow: true to enable Shadow DOM, and then you can use the :host selector and don't need the wrapping div in this example:

    @Component({ tag: 'my-button', styleUrl: 'button.css', shadow: true })
    export class Button {
      render() {
        return <slot />;
      }
    }
    

    css:

    :host {
      background: var(--primary-color, tomato);
      color: var(--light-color, white);
    
      display: block;
      padding: 1em 2em;
      border-radius: 0.2em;
      font-family: sans-serif;
      text-align: center;
      text-transform: uppercase;
    }
    

    Ionic 4 uses this concept a lot, so it might be worth having a look at their Stencil components: https://github.com/ionic-team/ionic/tree/master/core/src/components