Search code examples
javascriptpolymerpolymer-2.x

How to dynamically skin Polymer app


In a Polymer app I want to give the users the option to choose a certain theme from a set provided. So let's say that in a wrapper element I have a property called "theme" which holds a value like "dark", "light", etc. I would like to include a certain file with custom styles depending on that value.

So I have an element my-app-wrapper that includes some other ones if the user is not authenticated, or one called my-app for those that are. Now I tried to refactor it so that I have a new element called my-app-dark that extends my-app and just adds the import to the custom styles I need.

So in a file, let's say dark.html I have something like:

<custom-style>
  <style is="custom-style">
    html {
      --custom-theme: {
        --app-primary-color: #990AE3;
        --app-secondary-color: var(--paper-deep-orange-500);
      }
      ;
    }
  </style>
</custom-style>

And in my-app-wrapper I have something like this:

<template is="dom-if" if="[[_equals(theme, 'dark')]]" restamp>
  <my-app-dark></my-app-dark>
</template>
<template is="dom-if" if="[[!_includes(themes, theme)]]" restamp>
  <my-app></my-app>
</template>

The problem here is that in the wrapper element I need to import both my-app and my-app-dark. So even if I have that if statement and I use my-app the custom style imported by my-app-dark is still loaded and it applies its styles.

My only restriction is that I can't use lazy imports and load the file with Polymer.importHref, but even if I could, the import would happen after the CSS rules are parsed so it wouldn't work.


Solution

  • I experimented with theme changes with polymer 1.x using events and changing the theme programmatically. In the main may-app.html file I set colors to variables in the host element:

    <style include="shared-styles">
        :host {
             --some-color: black;
         }
    </style>
    

    These css color values were used throughout the child elements. When a change-theme event was called, I used this.customStyle['--some-color'] = 'white'; and Polymer.updateStyles(); to apply the color change.

    _onChangeTheme() {
        if (this.darkTheme) {
            //change to light theme
            this.customStyle['--some-color'] = 'white';
            this.set('darkTheme', false);
        } else {
            //change to dark theme
            this.customStyle['--some-color'] = 'black';
            this.set('darkTheme', true);
        }
        Polymer.updateStyles();
    }
    

    In Polymer 2 it should probably look something like this:

    _onChangeTheme() {
        if (this.darkTheme) {
            //change to light theme
            this.updateStyles('--some-color','white');
            this.set('darkTheme', false);
        } else {
            //change to dark theme
            this.updateStyles('--some-color','black');
            this.set('darkTheme', true);
        }
    }