Евгений, для поведения кнопок, которое Вы описали в вопросе, лучше подошли бы чекбоксы. Да, в разметке придется написать немного больше кода, но это будет правильный подход.
// За всю отрисовку состояния инпутов отвечает одна функция, опираясь на данные из состояния.
const render = (state, controls) => {
const activeCount = Object.values(state).filter(v => v === 'checked').length // Здесь получаем количество 'чекнутых' инпутов
if (activeCount === state.maxActiveCount) { // Никаких магических чисел.
controls.forEach(input =>
state[input.dataset.service] === 'checked' // input.dataset.service - достает значение из data атрибута в инпуте
? input.setAttribute("checked", "")
: input.setAttribute("disabled", "")
)
} else {
controls.forEach(input =>
state[input.dataset.service] === 'checked'
? input.setAttribute("checked", "")
: input.removeAttribute("disabled")
)
}
}
/* Здесь используем замыкание функции для доступа к состоянию. Реализуем сосотяние опираясь на количество инпутов. В реальных приложениях лучше использовать proxy или библиотеку для подписки на изменения состояния */
const createHandler = (controls = []) => {
const state = controls.reduce((acc, input) => {
const value = input.dataset.service
return {...acc, [value]: 'idle'}
},{maxActiveCount: 3}) // Как обсуждалось в комментариях добавим переменную которая регулирует количество активных кнопок
return ({target}) => { // Это обработчик событий
const value = target.dataset.service
state[value] = state[value] === 'idle' ? 'checked' : 'idle'
render(state, controls)
}
}
// Здесь находим форму и делигируем события инпутов на один обработчик событий
const service = document.getElementById('service')
const serviceControls = Array.from(service.elements)
const handleChange = createHandler(serviceControls)
service.addEventListener("change", handleChange)
.service {
display: inline-flex;
flex-wrap: wrap;
gap: 20px;
padding: 10px;
background-color: slateblue;
}
.control input { /*прячем инпут*/
appearance: none;
}
.control__button {
display: inline-flex;
justify-content: center;
align-items: center;
padding: 8px 16px;
border-radius: 10px;
text-wrap: none;
background-color: #DDDDDD;
cursor: pointer;
}
.service__control input:checked + .control__button {
background-color: #11AA11;
}
.service__control input:disabled + .control__button {
background-color: #FF5555;
}
<form class='service' id="service">
<label class="control service__control">
<input type="checkbox" data-service="gardens" />
<span class="control__button">тык раз</span>
</label>
<label class="control service__control">
<input type="checkbox" data-service="lawn" />
<span class="control__button"> тык два</span>
</label>
<label class="control service__control">
<input type="checkbox" data-service="planting" />
<span class="control__button">тык три</span>
</label>
<label class="control service__control">
<input type="checkbox" data-service="fourth-button" />
<span class="control__button">тык четыре</span>
</label>
<label class="control service__control">
<input type="checkbox" data-service="fifth-button" />
<span class="control__button">тык пять</span>
</label>
</form>
Теперь, это маштабируемый код, можете хоть 10 кнопок обработать и если Вам нужно куда-то отправлять данные с выбранных инпутов, Вам всего лишь останется добавить кнопку для отправки в разметку формы, повесить листенер на форму(которая уже есть) и написать обработчик на событие submit и все готово!)