Simple – HTML, CSS, JS

Local or Online Development

local: install Visual Studio Code. – Youtube Link

online: browse to https://vscode.dev/

Step One: Create a Project Folder
– File – Open Folder – ****
locate your code folder and create a subfolder for your project (to-do-list) and create a subfolder in that (v1)

Step Two: Create the FOUR files

  1. index.html
  2. style.css
  3. script.js
  4. mytasks.json

Step Three: Copy the code from below into the files

Step Four: Run your app

using local vscode – press F5 or click the run button.

using vscode online – open a browser and navigate to your code folder and open the html file.

HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JSON File To-Do List</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div class="container">
        <h2>Task Manager</h2>
        
        <div class="file-controls">
            <button id="open-btn">Open JSON File</button>
            <button id="save-btn" disabled>Save Changes</button>
        </div>

        <div class="input-group">
            <input type="text" id="todo-input" placeholder="New task..." disabled>
            <button id="add-btn" disabled>Add</button>
        </div>

        <ul id="todo-list"></ul>
        <p id="status-msg">Please open a .json file to begin.</p>
    </div>
    <script src="script.js"></script>
</body>
</html>

CSS

/* 1. Global Styles & Typography */
body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    background-color: #f8f9fa;
    color: #333;
    display: flex;
    justify-content: center;
    padding: 60px 20px;
    margin: 0;
}

/* 2. Main Container */
.container {
    background: #ffffff;
    width: 100%;
    max-width: 450px;
    padding: 30px;
    border-radius: 16px;
    box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08);
}

h2 {
    font-size: 1.5rem;
    margin-bottom: 25px;
    text-align: center;
    color: #2c3e50;
    font-weight: 600;
}

/* 3. File Controls Section */
.file-controls {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 25px;
    padding-bottom: 20px;
    border-bottom: 1px solid #edf2f7;
}

/* 4. Inputs and Buttons */
.input-group {
    display: flex;
    gap: 10px;
    margin-bottom: 25px;
}

input[type="text"] {
    flex: 1;
    padding: 12px 16px;
    border: 2px solid #e2e8f0;
    border-radius: 8px;
    font-size: 1rem;
    transition: border-color 0.2s ease;
}

input[type="text"]:focus {
    outline: none;
    border-color: #3182ce;
}

button {
    padding: 12px 20px;
    font-size: 0.95rem;
    font-weight: 500;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    transition: all 0.2s ease;
}

button:active {
    transform: translateY(1px);
}

/* Specific Button Colors */
#open-btn { background-color: #3182ce; color: white; flex: 1; }
#open-btn:hover { background-color: #2b6cb0; }

#save-btn { background-color: #805ad5; color: white; flex: 1; }
#save-btn:hover { background-color: #6b46c1; }

#add-btn { background-color: #38a169; color: white; }
#add-btn:hover { background-color: #2f855a; }

button:disabled {
    background-color: #cbd5e0 !important;
    cursor: not-allowed;
    opacity: 0.7;
}

/* 5. The Task List */
ul {
    list-style: none;
    padding: 0;
    margin: 0;
}

li {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 14px 16px;
    margin-bottom: 10px;
    background-color: #fdfdfd;
    border: 1px solid #edf2f7;
    border-radius: 8px;
    transition: background-color 0.2s;
}

li:hover {
    background-color: #f7fafc;
}

.del-btn {
    background-color: #fed7d7;
    color: #c53030;
    padding: 6px 12px;
    font-size: 0.85rem;
}

.del-btn:hover {
    background-color: #feb2b2;
}

/* 6. Status Messages */
#status-msg {
    margin-top: 20px;
    font-size: 0.85rem;
    color: #718096;
    text-align: center;
    font-style: italic;
}

Java Script

let fileHandle;
let tasks = [];

const openBtn = document.getElementById('open-btn');
const saveBtn = document.getElementById('save-btn');
const addBtn = document.getElementById('add-btn');
const input = document.getElementById('todo-input');
const todoList = document.getElementById('todo-list');
const statusMsg = document.getElementById('status-msg');

// 1. Open and Read the JSON File
openBtn.addEventListener('click', async () => {
    try {
        [fileHandle] = await window.showOpenFilePicker({
            types: [{ description: 'JSON Files', accept: { 'application/json': ['.json'] } }],
            multiple: false
        });

        const file = await fileHandle.getFile();
        const content = await file.text();
        
        // Parse JSON content (handle empty files with empty array)
        tasks = content ? JSON.parse(content) : [];
        
        enableApp(file.name);
        renderTasks();
    } catch (err) {
        console.error("File access denied or closed", err);
    }
});

// 2. Save the array back to the JSON File
saveBtn.addEventListener('click', async () => {
    if (!fileHandle) return;
    
    const writable = await fileHandle.createWritable();
    await writable.write(JSON.stringify(tasks, null, 2));
    await writable.close();
    
    statusMsg.innerText = "Changes saved to file!";
    setTimeout(() => statusMsg.innerText = `Editing: ${fileHandle.name}`, 2000);
});

// 3. UI Logic
function renderTasks() {
    todoList.innerHTML = '';
    tasks.forEach((task, index) => {
        const li = document.createElement('li');
        li.innerHTML = `<span>${task}</span><button class="del-btn" onclick="deleteTask(${index})">x</button>`;
        todoList.appendChild(li);
    });
}

function deleteTask(index) {
    tasks.splice(index, 1);
    renderTasks();
}

addBtn.addEventListener('click', () => {
    if (input.value.trim()) {
        tasks.push(input.value.trim());
        input.value = '';
        renderTasks();
    }
});

function enableApp(fileName) {
    input.disabled = false;
    addBtn.disabled = false;
    saveBtn.disabled = false;
    statusMsg.innerText = `Editing: ${fileName}`;
}

json data

[
  "Review Year 10 Science for Friday",
  "Daily Goal: Reach 10,000 steps",
  "Eat a health breakfast",
  "Buy chocolate from IGA",
  "Get uniform washed before work"
]