You can build a browser application with plain JavaScript and HTML. The trade-off is that your code must do work a frontend framework would otherwise handle: respond to events, change application state, and update the page to match. section 2.0 section 2.3
A small to-do app makes those responsibilities concrete:
- Keep fixed controls in HTML, but generate the to-do items in JavaScript because their contents depend on the current state. section 2.2 section 2.2.2
- Store the to-do descriptions in an array. Get references to the input, Add button, and list with document.getElementById(). section 2.2.3
- Attach event listeners. Input controls whether Add is enabled; a click or Enter adds a to-do when its description has at least three characters. section 2.2.3
- Create elements with document.createElement(), set their content, and append or replace them in the list. Use separate functions for a to-do’s read and edit views. section 2.2.3
Keep state and the page in step
To add a to-do, push its description into the array, render a list item, append that item to the page, then clear the input and disable Add. Removing one requires both splicing the array and removing its list item. Editing one requires changing the array entry and replacing the displayed item. Changing state alone does not update the page. section 2.2.3 section 2.3
Listing 2.6 Functions to add, remove, and edit to-dos (todos.js)
function addTodo() { #1
const description = addTodoInput.value
todos.push(description)
const todo = renderTodoInReadMode(description)
todosList.append(todo)
addTodoInput.value = ''
addTodoButton.disabled = true
}
function removeTodo(index) { #2
todos.splice(index, 1)
todosList.childNodes[index].remove()
}
function updateTodo(index, description) { #3
todos[index] = description
const todo = renderTodoInReadMode(description)
todosList.replaceChild(todo, todosList.childNodes[index])
}
The add, remove, and update functions show each state change paired with its corresponding DOM change. section 2.2.3
Load the JavaScript file as an ES module with a script element using type="module". Browser modules are deferred by default, so the HTML is parsed before this code runs. This approach works without a framework, but as interactions accumulate, application logic and imperative DOM manipulation can become mixed and verbose. section 2.2.2 section 2.3











