Inline template: light/dark mode switch

If your website has a light and a dark mode, then you would probably want your Piano template to react to color scheme changes accordingly. For a light/dark mode controlled by a user's operating system (with the help of the prefers-color-scheme CSS media query), just add this media query to the template and provide styles for the alternative version.

But if you have a button by hitting which a user can change their UI color scheme, it won't affect Piano templates by default. The templates are iframes, and in order to respond to any events on the parent page, they need to be "asked" to do so explicitly. Let's see how this interaction can be achieved.

Most probably there's going to be a small lag between mode switching on your website and a Piano template. Again, this is because it's in an iframe, and it takes some time to pass data, process and respond to it. We suggest a couple of ways to deal with it below.

DemoTo return from the demo page, please use the browser Back button. We were trying to make the demo as close to real life as possible, and did not provide any link to go back intentionally.

How-to

Setting up a template

There're 2 ways to set up an inline template: on your end or in Composer.

Sending a mode change event to the template

There're 2 moments when you need to let the Piano template know which mode is currently on: (1) when the template is loaded initially and (2) if a user switches it while the template is already there.

For the first case just send a custom variable to Piano before calling the template, using this code:

tp.push(['setCustomVariable', 'darkMode', false]);

Instead of the sample false value, please use your real mode value (boolean would fit best).

Also each time a user changes the mode from light to dark (or back), send a postMessage to the Piano iframe with the information about the current mode. Here is a code sample you might need to add to your JavaScript:

const pianoWindow = document.querySelector('.piano-container iframe');
pianoWindow.contentWindow.postMessage({ darkMode: { isOn: false } }, '*');

Instead of the .piano-container class name, please use your template container identifier.
Also send your actual mode state instead of the false value specified here as an example.

Describe styles in a template

In your template please add a class which would rule the template’s mode when being added or removed. Let’s say we have an uppermost node in the template with a class template. Add a class description template--dark (note: we use the BEM naming convention here, you may use any) and provide styles for the dark mode, both for the template itself and all its elements to be affected by the mode. For example:

.template--dark {
  color: #ffffff;
  background-color: #000000;
}

.template--dark .button {
  color: #000000;
  background-color: #ffffff;
}

Catching an event and changing the mode

In your template add some JavaScript code using the custom-script directive. Add a logic which would listen to a postMessage and change the template's mode according to the message it got. The code might look somewhat like that:

const template = document.querySelector('.template');
const templateScope = angular.element(template).scope();

window.addEventListener('message', (event) => {
  if (event.data.darkMode) {
    templateScope.custom.darkMode = message.data.darkMode.isOn;
  }
});

In this code we set the template's scope to add a variable there with the value of the mode state. We're using the custom object here because we pass the current mode value to the template as a custom variable which we then check in the markup (see further).

In your HTML find the uppermost (parent) tag and add an Angular condition that would add or remove the dark mode CSS class depending on the custom variable we get from the parent page or set in the JavaScript.

ng-class="{ 'template--dark': custom.darkMode }"

Dealing with blinking

In order to smooth the blinking down a bit, to make it less noticeable, we recommend using some simple animation in your template. It can be the transition effect on all properties you change together with the mode (typically it's a background and copy color).

As an alternative, you could think through a UI colorscheme of the template which would look contrast with both light and dark modes. Say, use blue or green color for the copy and CTA elements (a button on the demo template would be a nice example) — and set a transparent background to the template and all its parent nodes which might be white by default.

Specifying a template size

Piano's inline templates simply take 100% of the parent container width. By parent container we mean the <div> you specify on your end for the Piano template to show up. Regarding its height, the browser counts it automatically according to the template contents. So nothing needs to be defined. Instead, just let the Piano template be parsed freely — things like setting up a fixed height would prevent it from displaying correctly.