Is there a way to switch the classList between various buttons using a single JavaScript function?

I'm currently developing a straightforward add to cart container that also has the ability to toggle between different product sizes.

However, I am facing difficulties in achieving this functionality without having to create separate functions for each button.

Below is the JavaScript code snippet:

const sizeBtn = document.getElementById("sizebutton");
const sizeBtnTwo = document.getElementById("sizebutton1");
const sizeBtnThree = document.getElementById("sizebutton2");

sizeBtn.addEventListener('click', sizeBtnActive);
sizeBtnTwo.addEventListener('click', sizeBtnActive);
sizeBtnThree.addEventListener('click', sizeBtnActive);

function sizeBtnActive () {
  sizeBtn.classList.toggle('active');
  sizeBtnTwo.classList.toggle('active');
  sizeBtnThree.classList.toggle('active');
}

Including CSS styles for better understanding:

.size-btn.faded,
.size-btn.active {
  font-size: 12px;
  color: #c2c2c2;
  background-color: #f0f0f0;
  width: 38px;
  height: 42px;
  border-radius: 0.5rem;
  border: none;
  margin-right: 10px;
  margin-bottom: 35px;
  cursor: none;
}

.size-btn.active {
  color: #ffff;
  background-color: #000000;
  box-shadow: 1px 2px 10px rgba(0, 0, 0, 0.3);
  transition: 1.5s ease;
  cursor: pointer;
}

If you can provide any guidance or suggestions on how to improve this code, it would be highly appreciated.

I have attempted to find solutions by researching similar issues online, but none of them have been effective so far. My goal is to toggle between each button individually without activating all of them at once.

Answer №1

One way to simulate a radio button group is by creating a button group and toggling a data attribute on the active button.

Simply add a global listener for the button group and log the value after each change.

// Global button group listener
window.addEventListener('click', (e) => {
  if (e.target.closest('.button-group')) {
    toggleButtonGroup(e.target);
  }
});

// Log the new value after each change
document.querySelector('.size').addEventListener('click', (e) => {
  setTimeout((buttonGroup) => {
    console.log('Value:', getButonGroupValue(buttonGroup));
  }, 100, e.currentTarget);
});

// Toggle active state of buttons
function toggleButtonGroup(button) {
  const buttonGroup = button.closest('.button-group');
  buttonGroup.querySelectorAll('button').forEach((currButton) => {
    if (currButton === button && !currButton.dataset.active) {
      currButton.dataset.active = true;
    } else {
      delete currButton.dataset.active;
    }
  });
}

// Value accessor
function getButonGroupValue(buttonGroup) {
  return buttonGroup?.querySelector('[data-active]')?.value;
}
.button-group {
  display: inline-flex;
  border: thin solid grey;
  width: fit-content;
}

.button-group button {
  background: #CCC;
  border: none;
  min-width: 2.5rem;
  padding: 0.25rem;
}

.button-group button:hover {
  background: #DDA;
  cursor: pointer;
}

.button-group button[data-active] {
  background: #FFF;
}

.button-group button[data-active]:hover {
  background: #FFA;
}
<label>Size: </label>
<div class="button-group size">
  <button type="button" value="xs">XS</button>
  <button type="button" value="s">S</button>
  <button type="button" value="m" data-active>M</button>
  <button type="button" value="l">L</button>
  <button type="button" value="xl">XL</button>
  <button type="button" value="xxl">XXL</button>
</div>

Answer №2

I am looking to create a toggle functionality where each button can be activated individually, without activating all at once.

The most efficient way to achieve this is by assigning a common class name to all the buttons first.

<button class="btn"></button>
<button class="btn"></button>
<button class="btn"></button>

Then, we can select all these buttons using querySelectorAll and use a forEach loop to deactivate all of them initially, and then activate only the selected one:

const btns = document.querySelectorAll(".btn")

function disableAllButtons() {
    btns.forEach(btn => {
        btn.classList.remove("active")
    })
}

btns.forEach(btn => {
    btn.addEventListener(() => {
        disableAllButtons()

        btn.classList.add("active")
    })
})

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

obtain an inner element within a container using the class name in a div

I am attempting to locate a span element with the class of main-tag within a nested div. However, I want to avoid using querySelector due to multiple elements in the HTML file sharing the same class and my preference against using IDs. I realize there mig ...

Does the react key have scope limited to the local environment or does it have

After reading this intriguing article discussing the use of the index as a react key, I began to ponder. Imagine having two distinct lists: <List1> <el key="1" /> <el key="2" /> </List1> <List2> <other-el key="1" / ...

Verify if a certain value exists in an array while using ng-if inside ng-repeat

Currently, I have a loop using ng-repeat that goes through a list of wines obtained from an API. Alongside this, there is an array variable containing all the IDs of wines that have been marked as favorites and retrieved from the database. My goal is to sh ...

What is the best way to eliminate the "onclick" attribute from an HTML element using JavaScript?

Is there a way to make my code only execute the onlick function after a button is pressed? I want to prevent any action from happening before that. <!-- deactivate onclick function --> <div class="boardsection2" id="2_8_7" oncl ...

Using Vue3 to conditionally display a child div based on the class of its parent div

Just starting out with Vue, I'm currently experimenting with the active classes feature from this Vue3 carousel plugin. My goal is to only show the text and link divs for the carousel__slide--active class, but at the moment, all carousel__items are di ...

Having trouble navigating through multiple layers of nested array data in react js

I need help understanding how to efficiently map multiple nested arrays of data in a React component and then display them in a table. The table should present the following details from each collection: title, location, description, and keywords. Below ...

How can I display a calendar with a complete month view using ng-repeat?

I was trying to replicate a table similar to the one shown in this image: (disregard the styling). I am struggling with how to properly format the data to create a similar table in HTML. $scope.toddlers = [ { "name": "a", "day": 1, "total": 3 }, { ...

Vertical tab design in Bootstrap does not automatically switch tabs

I'm managing two separate tab boxes that switch content when clicked or over a 5-second period. The left box is functioning correctly, but the right box is changing the active state without updating the content. Here's the HTML for the left box ...

Unable to substitute 'npm run build' for 'webpack' command

I'm having trouble with npm run build not calling webpack as expected. I've modified the script in my package.json file, but it didn't work. I'm using Linux. Here is a snippet from my package.json file: { "name": "learn-webpack", ...

Update the datapicker calendar to select dates within a one-year range

Apologies for the incomplete code snippet — it's just a rough representation in HTML. $('#Datepicker1').datepicker( { changeYear: true, dateFormat: 'dd.mm.yy', maxDate: 0, ...

Tips for incorporating images into an `.mdx` file located outside of the `public/` directory with the `next-mdx-remote` package in Next JS

I am currently developing a blog using next-mdx-remote and I am facing an issue with incorporating images in the .mdx file that are located outside of the public/ folder. If you would like to check out the complete code for my blog project, it is availabl ...

Using knockout to data bind a function to an onclick event that takes in multiple parameters

I've scoured the internet and experimented with various methods, but I'm encountering an issue where the click function intermittently fails to fire. Below is my HTML code snippet: <input type="radio" data-bind="checked:a, checkedValue: 0 ...

Access real-time information via JSON

I am facing a logical thinking challenge. Successfully retrieving data from a PHP file via JSON, but now encountering a slight issue. My goal is to retrieve various headlines - main and sub headlines. Each main headline may contain an unknown number of su ...

Adjust the size and position of the text input field

I'm struggling to find a way to both resize and move the box without one action interfering with the other. Whenever I attempt to change the size of the box, it triggers the move event at the same time. Clicking on the box should make it resizable, bu ...

What are the steps for making Ajax calls?

I have been working on a Wikipedia viewer for my freecodecamp project. However, I am facing issues with the AJAX request as it keeps failing every time without returning any results. var url, value; $(document).ready(function() { $("button").on("click ...

Attempting to call setState (or forceUpdate) on a component that has been unmounted is not permissible in React

Hello everyone! I am facing an error message in my application after unmounting the component: Warning: Can't call setState (or forceUpdate) on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, canc ...

What is the best way to conceal the main list but still show the nested list within?

I'm looking for a way to conceal the main parent of a sub-list while still displaying the nested list. Furthermore, I need to ensure that the parent element doesn't occupy any space on the page when hidden. HTML <ul> <li class="par ...

Navigating through objects within arrays within objects in Angular

I seem to be encountering some difficulty in displaying data from an API call on Mapbox. Only one marker is showing up on the map instead of the expected 10 markers. I suspect there might be an issue with my ng-repeat implementation, but I can't pinpo ...

Determine the minimum and maximum width of jQuery UI resizable during the "resizestart" event

As a newcomer to Javascript, I am facing challenges navigating my way around. Currently, I am attempting to create a jQuery plugin that will facilitate resizing elements using the jQuery UI resizable plugin. My goal is to implement logic that dynamically ...

Transforming Thomas J Bradley's signature pad JSON into a PNG file using C# programming language

I have been experimenting with the Signature Pad plugin developed by Thomas J Bradley and successfully converted JSON signature to PNG using PHP. Now I am looking to achieve the same result using C#. There is a supplemental class called SignatureToImageDo ...