Build a Theme Switcher - Build a Theme Switcher

Tell us what’s happening:

I am currently trying to display text content in an element that has the aria-live attribute, so that any users using assistive technology can be informed of changes in the webpage. However, it doesn’t seem to be functioning properly. Furthermore, the body element within the HTML document doesn’t seem to have been given a class attribute from the script even though I had done so.

I am wondering what areas I am overlooking and what changes I could make to utilize .toggle instead of the approach I currently have.

Your code so far

<!-- file: index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Theme Switcher</title>
  <link rel="stylesheet" href="./styles.css">
</head>
<body>
  <button id="theme-switcher-button" aria-haspopup="true" aria-expanded="false" aria-controls="theme-dropdown">Switch Theme</button>
  <ul id="theme-dropdown" role="menu" aria-labelledby="theme-switcher-button" hidden>
    <li id="theme-yellow" role="menuitem">Yellow</li>
    <li id="theme-red" role="menuitem">Red</li>
  </ul>
  <p aria-live="polite"></p>
  <script src="./script.js"></script>
</body>
</html>
/* file: styles.css */
body {
  margin: 0;
  font-family: sans-serif;
  transition: background 0.3s, color 0.3s;
}

ul {
  margin: 0;
  padding: 0;
  cursor: pointer;
}

li {
  list-style-type: none;
}

#status {
  text-align: center;
  min-height: 20px;
}
/* file: script.js */
const themes = [
  {
    name: "yellow",
    message: "Welcome to the bee hive!"
  },
  {
    name: "red",
    message: "Welcome to the blood pool!"
  }
];

const buttonEl = document.querySelector("#theme-switcher-button");
const dropDownEl = document.querySelector("#theme-dropdown");
const liveRegionEl = document.querySelector('[aria-live="polite"]');
const bodyEl = document.querySelector("body");
let msgEl = "";

buttonEl.addEventListener("click", () => {
  if (buttonEl.getAttribute("aria-expanded") === "true") {
    buttonEl.setAttribute("aria-expanded", "false");
    dropDownEl.hidden = true;
  } else {
    buttonEl.setAttribute("aria-expanded", "true");
    dropDownEl.hidden = false;
  }

  // ## Want to utilize this approach to simplify things but it doesn't work. ##
  // dropDownEl.classList.toggle("hidden");
  // buttonEl.classList.toggle("aria-expanded");
});

dropDownEl.addEventListener("click", (event) => {
  document.body.style.backgroundColor = event.target.textContent;
  bodyEl.classList.add("class", `theme-${event.target.textContent.toLowerCase()}`);

  // Trying to access value for 'message' property in array of objects.
  themes.forEach(obj => {
    for (const prop in obj) {
      if (obj.hasOwnProperty("name") && obj[prop] === event.target.textContent.toLowerCase()) {
        if (prop === "message") {
          msgEl = obj[prop];
        }
      }
    }
  });

  liveRegionEl.textContent = msgEl;
});

// console.log(themes[0].message);

Console:

26. When a user clicks on the #theme-switcher-button and selects a theme, the corresponding theme-<name> class should be added to the body element.
27. When a user clicks the #theme-switcher-button and selects a theme, a message related to the selected theme from the themes array should be displayed in the aria-live="polite" element.

Challenge Information:

Build a Theme Switcher - Build a Theme Switcher

what is happening instead? what part of your code is dedicated to adding the text inside the aria-live element?

what part of your code is dedicated to updating the class on the body element?

1 Like

This section of code is responsible for adding the text inside the aria-live element

// Trying to access value for 'message' property in array of objects.

  themes.forEach(obj => {

    for (const prop in obj) {

      if (obj.hasOwnProperty("name") && obj[prop] === event.target.textContent.toLowerCase()) {

        if (prop === "message") {

          msgEl = obj[prop];

        }

      }

    }

  });




  liveRegionEl.textContent = msgEl;

This section of the script is responsible for updating the class on the body element

document.body.style.backgroundColor = event.target.textContent;

  bodyEl.classList.add("class", `theme-${event.target.textContent.toLowerCase()}`);

Both of these code snippets are nested within the same addEventListener which is the following
dropDownEl.addEventListener("click", (event) => {

dropDownEl represents the unordered-list which represents the drop-down menu and it’s listed items as options for changing the background color.
const dropDownEl = document.querySelector("#theme-dropdown");

Elements in HTML

<ul id="theme-dropdown" role="menu" aria-labelledby="theme-switcher-button" hidden>

    <li id="theme-yellow" role="menuitem">Yellow</li>

    <li id="theme-red" role="menuitem">Red</li>

  </ul>

  <p aria-live="polite"></p>

looking at the body element you are adding also a class named class
image

when I click on the other button theme-yellow is not removed
image

I see a style attribute changing on body, remove that part of the code, use only the classes to change the color of body, so you can visually see when they are added or not


I added that console.log, it never runs
obj[prop] === event.target.textContent.toLowerCase())
prop === "message"

why are you iterating on the properties of the object? the two conditions can never be true at the same time

you don’t need to iterate over the props, you know which two props you have

1 Like

Noted, I made the following changes:

bodyEl.setAttribute("class", `theme-${event.target.textContent.toLowerCase()}`);

// Replaced for...of loop with classic loop due to bracket notation (for accessing index) not working with dot notation

  for (let i = 0; i < themes.length; i++) {

    if (themes[i].name === event.target.textContent.toLowerCase()) {

      msgEl = themes[i].message;

    }

  }




  liveRegionEl.textContent = msgEl;

CSS File

body [class=“theme-yellow”] {

background-color: yellow;

}

body [class=“theme-red”] {

background-color: red;

}

However, the background-color for the body doesn’t seem to change upon clicking on the different options.

you should review what the space means in selectors

you can use much simpler selectors anyway

how do you select a class?

1 Like

I managed to resolve the issue by omitting ‘body’ from the CSS selector.

For selecting a class you would use dot notation as such: ‘.className {}’.

With some of the other changes the lab now passes all test cases, thank you!

when you write body [class=“theme-red”] you are selecting [class=“theme-red”] that is descendand of body

spaces have meaning in selectors, keep that in mind

1 Like

Ah, I see. Thank you for informing me, I’ll keep note of that going forward!

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.