Смену иконки можно реализовать без дополнительного JS. Ниже добавил два варианта решения задачи.
Первый пример:
Берем две иконки SVG. Допустим это Луна и Солнце. Далее нужно будет закодировать SVG для использования в CSS и сделать это можно, например, с помощью этого
инструмента.
Далее обработанные SVG применим для иконки. Сама иконка будет представлять из себя псевдоэлемент, хотя можно использовать и HTML тег, например span, но всё же не стоит добавлять лишние сущности в разметку, если в этом нет нужды.
Добавляем в кнопку псевдоэлемент для иконки:
.btn::after {
content: "";
position: relative;
display: inline-flex;
width: 20px;
height: 20px;
background-size: contain;
background-repeat: no-repeat;
}
Далее на основе выбранной темы, будем менять бекграунд иконки. Так как через JS происходит добавление класса к корневому элементу с названием текущей темы - можно воспользоваться этим и через CSS без лишних проблем менять оформление иконке.
Светлая тема:
.light .btn::after{
background-image: url("data:image/svg+xml...//иконка-солнца");
}
Темная тема:
.dark .btn::after {
background-image: url("data:image/svg+xml...//иконка-луны");
}
Хотя этот вариант и кажется простым и доступным, всё же он хранит в себе некоторые недостатки.
1. Нельзя просто взять и изменить цвет иконки при наведении.
2. При желании изменить дефолтный цвет иконки, придётся взять оригинальный SVG - вектор, перекрасить его и заново закодировать, после чего обновить значение в CSS файле.
3. Если иконки большие по обьему, они будут увеличивать размер CSS файла, но тут есть решение этой проблемы. Перед конвертацией SVG в CSS, прогоняем вектор через SVGO. Правда и это порой не сильно помогает.
Второй вариант:
Добавить обе иконки в кнопку, в качестве SVG, задать иконкам разные классы и по дефолту скрыть обе иконки, например:
<svg class="icon__light">
// содержимое SVG
</svg>
<svg class="icon__dark">
// содержимое SVG
</svg>
И через CSS менять видимость иконок.
Пример:
.icon__light,
.icon__dark {
display: none;
}
.light .icon__light {
display: block;
}
.dark .icon__dark {
display: block;
}
У этого подхода тоже имеются свои подводные камни, впрочем, как и у любого способа решить ту или иную задачу, но минусами этого подхода намного проще бороться.