loading...

How to make a switch start in the appropriate position

yujiri8 profile image Ryan Westlund ・2 min read

I ran into a problem today while refactoring my website to be less Javascript dependent (previously the navbar was a web component meaning no navigation appeared without JS), and I found the solution pretty interesting.

The situation: you have a dark mode switch that saves the user's preference in local storage. I use the mwc-switch component, but I imagine this would be relevant to other switch components.

The symptom: when the page is loaded with the preference set to dark, the switch starts in its light mode position and slides to the dark mode position.

The difficulty, of course, is that the switch can't start out with its attribute set correctly because it depends on Javascript and the initial DOM structure can't depend on Javascript. Having Javascript that sets the switch state run before DOMContentLoaded (by putting it in the global scope) won't work because you have to make sure the switch is actually loaded into the DOM before you reach for it to touch it. Having Javascript dynamically insert the switch on document load also won't work because then you see the switch appear when you load the page, instead of it being there from the start.

When my top bar was a web component, I didn't have this problem, and I didn't fully understand why that made the difference until I thought about it: when the switch is embedded in a render template with its attribute set declaratively, it renders correctly the first time, but still doesn't have to wait for DOMContentLoaded. I lost that when I moved the switch outside of a web component and into the top-level DOM.

So the solution was to make a thin wrapper component just to hold the switch and set its attribute properly. Problem solved, the navbar no longer depends on Javascript, and I improved both my layout and my page template script while I was at it.

Discussion

pic
Editor guide