Когда мы имеем дело с большими вложенными списками, было бы хорошо сделать их как можно компактнее. JavaScript отлично справится с поставленной задачей.

Раскрывающийся список на JavaScript

Когда мы имеем дело с большими вложенными списками, было бы хорошо сделать их как можно компактнее. JavaScript отлично справится с поставленной задачей.


HTML разметка

Сделаем HTML разметку для раскрывающегося списка. Для этого создадим вложенные в друг друга списки.

<ul class="list" id="list">
  <li>Сладости
    <ul>
      <li>Конфеты
        <ul>
          <li>Мармелад</li>
          <li>Батончики</li>
          <li>Ассорти</li>
          <li>Карамель</li>
        </ul>
      </li>
    </ul>
  </li>

  <li>Выпечка
    <ul>
      <li>Торты
        <ul>
          <li>Трюфельный</li>
          <li>Наполеон</li>
          <li>Птичье молоко</li>
          <li>Павлова</li>
        </ul>
      </li>
    </ul>
  </li>

  <li>Напитки
    <ul>
      <li>Соки
        <ul>
          <li>Апельсиновый</li>
          <li>Яблочный</li>
          <li>Персиковый</li>
          <li>Томатный</li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

CSS код

На месте убранных дефолтных маркеров, с помощью JavaScript будут переключаться классы для замены плюса на минус и наоборот. Для раскрытия пункта списка, нужно нажать на плюс. Для сокрытия, нажать на минус.

body {
    font-size: 20px;
    font-weight: 500;
    font-family: sans-serif;
}

ul li {
    list-style: none; /* убираем дефолтные маркеры */
}

.list span {
    cursor: pointer;
}

.hide::before {
    content: "+"; /* украшательство вместо маркера */
}

.show::before {
    content: "-"; /* украшательство вместо маркера */
}

JavaScript код

Пройдемся в цикле for of по всем тегам li и обернем их содержимое в тег span с классом show. Тегом span мы ограничим область для клика мышкой, класс show служит чисто оформительским целям. Почему мы заранее не внесли span в разметку? Тогда пришлось для каждого добавленного нового пункта меню через админку, вручную прописывать тег span.

for (let li of list.querySelectorAll('li')) {
    let span = document.createElement('span'); /* создание span */
    span.classList.add('show'); /* добавление класса для span */
    li.prepend(span); /* вставить span внутри li */
    span.append(span.nextSibling) /* присоединить к span следующий узел */
}

Будем отлавливать клики по всем элементам списка и запускать функцию. Если клик не попал в span, то ничего не произойдет. Получим дочерний список (содержимое ul) - переменная childrenList. Проверяем, существует ли вложенный дочерний список? Если есть, то его нужно скрыть или показать с помощью методов add и remove.

list.onclick = function(event) {
    if (event.target.tagName != 'SPAN') return;

    let childrenList = event.target.parentNode.querySelector('ul');
    if (!childrenList) return;
    childrenList.hidden = !childrenList.hidden;

    if (childrenList.hidden) {
        event.target.classList.add('hide');
        event.target.classList.remove('show');
    }

    else {
        event.target.classList.add('show');
        event.target.classList.remove('hide');
    }
}

Посмотрите демо на CodePen