Создание элемента и его добавление на страницу — отдельные действия. Например, для списка используйте такой код:
const list = document.querySelector('#items');
const item = document.createElement('li');
item.textContent = 'Новый пункт';
list.append(item);
В HTML при этом должен существовать контейнер, например <ul id="items"></ul>. Выполняйте код после появления контейнера в DOM. Метод createElement создает объект узла, но сам по себе не выбирает, где этот узел показать. Именно append присоединяет его к указанному родителю.
Для обычного пользовательского текста используйте textContent. Тогда символы вроде угловых скобок останутся текстом и не будут интерпретированы как HTML-разметка. Это особенно полезно для значений из поля ввода. Если создается кнопка, задайте ей осмысленный текст и нужный тип, чтобы внутри формы она случайно не отправляла данные.
Каждый новый пункт создавайте отдельным вызовом createElement. Если многократно добавлять один и тот же объект узла, он будет перемещаться, а не превращаться в несколько независимых копий. Это распространенная причина, по которой из всего цикла на странице остается один пункт.
Обработчики событий можно назначить созданному элементу до добавления или после него. Для большого списка иногда удобнее один обработчик на контейнере, но для первого примера достаточно простого подхода.
Если ничего не появилось, сначала проверьте переменную list. Значение null означает ошибку поиска или слишком ранний запуск. Затем убедитесь, что код дошел до append и что CSS не скрывает добавленное содержимое. Создание переменной с текстом еще не создает DOM-элемент.
Ответить на вопрос