<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Demo</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ" crossorigin="anonymous">
</head>
<style>
/* Make sure error message always takes up space
to avoid list going down when error appears,
also see inline style on .invalid-feedback div */
.is-invalid + .invalid-feedback {
visibility: visible !important;
}
</style>
<body>
<div class="bg-white">
<template id="item-template">
<li class="mt-4">
<span class="name"></span>
<button class="btn btn-danger">X</button>
</li>
</template>
<div class="container-fluid">
<h1 class="mt-2">Tasks</h1>
<form>
<div class="row g-2 mt-4">
<div class="col-12 col-sm">
<input type="text" name="name" class="form-control">
<div class="invalid-feedback" style="display: block; visibility: hidden;">
Name is required
</div>
</div>
<div class="col-12 col-sm-auto">
<button type="submit" class="btn btn-primary w-100">+</button>
</div>
</div>
</form>
<ul id="items" class="overflow-y-auto" style="height: calc(100vh - 184px);"></ul>
</div>
<script>
const form = document.querySelector('form');
const list = document.querySelector('#items');
form.onsubmit = function(evt) {
evt.preventDefault();
if (form.name.value.trim() == '') {
form.name.classList.add('is-invalid');
const removeInvalid = () => form.name.classList.remove('is-invalid');
form.name.oninput = removeInvalid
form.name.onblur = removeInvalid
return
}
const template = document.querySelector('#item-template').content.cloneNode(true);
const item = template.querySelector('li');
const span = item.querySelector('span');
span.textContent = form.name.value;
const button = item.querySelector('button');
button.onclick = function() {
if (confirm(`Delete '${span.textContent}'?`)) {
item.remove();
}
}
list.appendChild(item);
form.name.value = '';
form.name.classList.remove('is-invalid');
}
</script>
</div>
</body>