При клике проверяем, у скольких элементов класс уже есть, если максимум достигнут - класс не добавляем:
const itemSelector = '.item';
const activeClass = 'active';
const maxActive = 3;
const onMaxActiveClick = () => alert(`больше ${maxActive} нельзя`);
// делегирование, назначаем обработчик клика один раз для всех элементов
document.addEventListener('click', function(e) {
const item = e.target.closest(itemSelector);
if (item) {
const active = document.querySelectorAll(`${itemSelector}.${activeClass}`);
if (active.length < maxActive || item.classList.contains(activeClass)) {
item.classList.toggle(activeClass);
} else {
onMaxActiveClick();
}
}
});
// или, назначаем обработчик клика каждому элементу индивидуально
let activeCount = 0;
for (const n of document.querySelectorAll(itemSelector)) {
n.addEventListener('click', onClick);
activeCount += n.classList.contains(activeClass);
}
function onClick({ currentTarget: item }) {
if (activeCount < maxActive || item.classList.contains(activeClass)) {
activeCount += item.classList.toggle(activeClass) ? 1 : -1;
} else {
onMaxActiveClick();
}
}