Brian Kiernan
AstroUXDS
Published in
6 min readSep 22, 2022

--

Astro UXDS Tutorial: This quick four-step tutorial will show you how to implement a light to dark theme Switch without losing the user’s preferred state.

Step One: Setup an HTML File with Astro Fonts, CSS, and JS Assets

To start your setup, simply open your terminal and make a directory.

mkdir astro-theme-switch

Navigate into the directory.

cd astro-theme-switch

Create your index.html file.

touch index.html

Open the file in your code editor.

code .

Serve the index.html file by using the Live Server extension in VS Code.

Use the Emmet html:5 file template.

Rename title and save it.

<title>Astro Theme Switch</title>

After reloading, the screen will be white. You’re now ready to add the assets: fonts, Cascading Style Sheets (CSS), and JavaScript (JS). Begin with Roboto Mono and Roboto from Google Fonts. Next, bring in the CSS and then the JS. These both come from unpkg.com.

Fonts

<link
href="https://fonts.googleapis.com/css2? family=Roboto+Mono:wght@400&family=Roboto:wght@200;300;400;500;600;8 00&display=swap"
rel="stylesheet"
/>

CSS

<link
rel="stylesheet"
href="https://unpkg.com/@astrouxds/astro-web-components@6.12.1/dist/astro-web-components/astro-web-components.css"
/>

JS

<script
type="module"
defer
src="https://unpkg.com/@astrouxds/astro-web-components@6.12.1/dist/astro-web-components/astro-web-components.esm.js"
></script>

With that complete, the background should be dark.

Step Two: Create a Global Status Bar with a Switch

To begin, let’s start by adding the Astro “global-status-bar” within the document body tags.

<body><rux-global-status-bar
include-icon="false"
app-domain="Astro"
app-name="Theme Switch"
app-version="v6.12.1"
menu-icon="apps"
username=""
app-state-color=""
app-state=""
></rux-global-status-bar>
</body>

If you are new to web components, they may look strange at first, just remember they are essentially custom html elements that you give a name.

Next, lets add the “clock” in the default slot of the “global-status-bar”

  app-state=""
>
<rux-clock></rux-clock></rux-global-status-bar></body>

Since <rux-clock></rux-clock> is in the default slot, you won’t need to add a slot attribute.

Lastly, let’s add the “switch” to the “right-side” slot and give it an id=”theme-switch” to be used in the JS later.

  <rux-clock></rux-clock>  <rux-switch slot="right-side" id="theme-switch">
<rux-icon
id="theme-icon"
slot="label"
icon="brightness-3"
size="small"
></rux-icon>
</rux-switch>
</rux-global-status-bar></body>

It’s important to note a few specifics:

The icon you’ll use is in the “label” slot; this will put it directly to the right of the “switch” and allow that icon to be clickable.

The brightness-3 icon will have quarter moon look.

The wb-sunny icon will have sun look.

You now have a Global Status Bar!

Step Three: Wire-up the Theme Switch

In this step, you’ll wire-up the theme Switch to toggle between the dark and light modes by adding a class of light-theme or dark-theme on the body tag.

<body class=“light-theme”>

By doing this, the theme is now in light mode.

Although the theme is now in light mode, it is not yet wired to the “switch”.

Add the JS

</body><script>
const body = document.querySelector('body');
const themeSwitch = document.getElementById('theme-switch');
const themeIcon = document.getElementById('theme-icon');
const darkIcon = 'brightness-3';
const darkTheme = 'dark-theme';
const lightIcon = 'wb-sunny';
themeSwitch.addEventListener('click', e => {
if (!e.target.checked) {
body.className = lightTheme;
themeIcon.icon = lightIcon;
return;
}
body.className = darkTheme;
themeIcon.icon = darkIcon;
});
</script>

You can now use the Switch to toggle between the dark and light themes.

It’s important to note a few specifics:

Dark is the default theme.

When you reload the page, it goes back to the default theme.

To correct this, you will need to persist the users preferred mode.

Step Four: Persist the User’s Preferred Theme with Local Storage

For this last step, you’ll add two new variables (themeName and themePreference) and persisting the theme using the browsers localStorage api.

</body><script>
const body = document.querySelector('body');
const themeSwitch = document.getElementById('theme-switch');
const themeIcon = document.getElementById('theme-icon');
const darkIcon = 'brightness-3';
const darkTheme = 'dark-theme';
const lightIcon = 'wb-sunny';
/********* add this **********/
const themeName = 'astro-theme';
const themePreference = window.localStorage.getItem(themeName);
if (themePreference) {
const preference = JSON.parse(themePreference);
body.className = preference.class;
themeIcon.icon = preference.icon;
themeSwitch.checked = preference.icon === lightIcon;
}
/********** end add new ************/
themeSwitch.addEventListener('click', e => {
if (!e.target.checked) {
/************ add this ***********/
const preference = { class: lightTheme, icon: lightIcon };
window.localStorage.setItem(themeName, JSON.stringify(preference));
/********** end add new ************/
body.className = lightTheme;
themeIcon.icon = lightIcon;
return;
}
/************* add this ************/
const preference = { class: darkTheme, icon: darkIcon };
window.localStorage.setItem(themeName, JSON.stringify(preference));
/************ end add new **********/
body.className = darkTheme;
themeIcon.icon = darkIcon;
});
</script>

It’s important to note a few specifics:

For themePreference, the constant is getting the item of themeName that could or could not exist.

If the themePreference exists, parse that object that has a class property and an icon property.

If the theme Switch is going to be checked depends on if it’s equal to light icon. If it is equal to light icon, the Switch goes in the checked mode. If it is not, it stays in unchecked mode.

Moving on from there, set the local storage based on the ‘click’ event. Before you assign attributes, go to where you’ve created the Preference object. This is where it has the class and icon property. For this tutorial, set the Preference to class of light theme and the Icon of light icon. Then, set the local storage item of theme Name using ‘astro-theme’, as before, and stringify Preference.

Create the Preference object with a class of dark theme and an Icon of dark icon and set that local storage item to theme Name again. After that, stringify Preference. That will take care of setting local storage for the dark theme.

You’ll see now that while using the Switch to go between light and dark modes, it persists when you refresh. This is the same outcome if you’re in dark mode.

Congrats! You now know how to implement a light to dark theme Switch without losing the user’s preferred state.

Here’s a link to the final code which is on CodeSandbox.

** FYI: CodeSandbox takes a moment or two to load all the resources **

https://codesandbox.io/s/astro-theme-switch-jt09uo?file=/index.html

I’m Brian Kiernan, a Rocket Communications front-end developer on the Astro UXDS team. We focus on the development of space-based applications that are open-source and free to the global community. For more about what we do, visit us at astrouxds.com.

Thank you for following along. This tutorial uses Astro 6, but it will also work with later versions.

--

--