Chapter 49 — Capstone Build Part 2: Behaviour and Data
Section 1 — The shape of the app state
This section covers the shape of the app state. The state is one object with four parts: a tasks array, a notes array, a filter value, and a search query. A single shape, written down before any code, prevents the rest of the chapter from inventing new structures on the fly.
Thinking about the shape of the app state in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat the shape of the app state as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through the shape of the app state in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with the shape of the app state for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When the shape of the app state feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects the shape of the app state to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
const state = { tasks: [], notes: [], filter: 'all', query: '' };
One state object holds the whole dashboard, so rendering, filtering and saving all read from the same place instead of from scattered variables.
A common mistake with the shape of the app state is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on the shape of the app state, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Change state first and then re-render, so the display can never drift away from the data it claims to show.
Check: What is one thing you would check about the shape of the app state in your own MyDay Dashboard before moving on?
Section 2 — Seed data for a first run
This section covers seed data for a first run. On a first run the dashboard shows a few generic example tasks and notes, such as a task to plan the day and a note about the dashboard itself. Seed data must be generic, never personal, because it may appear in screenshots.
Thinking about seed data for a first run in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat seed data for a first run as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through seed data for a first run in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with seed data for a first run for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When seed data for a first run feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects seed data for a first run to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
localStorage.setItem('myday-data-v1', JSON.stringify(state));
Saving means turning the state into text and storing it under one key, and loading is the reverse: read the text and turn it back into data.
A common mistake with seed data for a first run is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on seed data for a first run, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Keep functions small and named for one job, because a function that adds, saves and renders at once is hard to test and hard to fix.
Check: What is one thing you would check about seed data for a first run in your own MyDay Dashboard before moving on?
Section 3 — Loading data from localStorage
This section covers loading data from localstorage. Loading reads the stored text under the key myday-data-v1, parses it, and checks that the result has the expected shape before using it. A careful load is the difference between a dashboard that remembers and one that crashes on old data.
Thinking about loading data from localstorage in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat loading data from localstorage as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through loading data from localstorage in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with loading data from localstorage for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When loading data from localstorage feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects loading data from localstorage to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
function renderTasks() {
taskList.innerHTML = '';
visibleTasks().forEach(task => taskList.append(createTaskItem(task)));
}
Rendering clears the list and rebuilds it from the current visible tasks, which guarantees the screen matches the state after every change.
A common mistake with loading data from localstorage is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on loading data from localstorage, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Handle the empty case deliberately, because a dashboard with no tasks yet is a normal state, not an error. Validate input at the point of entry and give a plain message, so the user learns what to fix without losing what they typed.
Check: What is one thing you would check about loading data from localstorage in your own MyDay Dashboard before moving on?
Section 4 — Saving data to localStorage
This section covers saving data to localstorage. Saving stringifies the state and writes it under the same key after every meaningful change, such as adding or completing a task. Saving often is safer than saving only when the page closes, which may never happen cleanly.
Thinking about saving data to localstorage in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat saving data to localstorage as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through saving data to localstorage in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with saving data to localstorage for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When saving data to localstorage feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects saving data to localstorage to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
taskList.addEventListener('click', (event) => {
const button = event.target.closest('button');
if (!button) return;
});
One listener on the list can handle clicks on any of its buttons, including buttons added later, by checking which button was actually pressed.
A common mistake with saving data to localstorage is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on saving data to localstorage, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Validate input at the point of entry and give a plain message, so the user learns what to fix without losing what they typed. Save after every meaningful change, not only when the page closes, because a closed tab should not lose a finished task.
Check: What is one thing you would check about saving data to localstorage in your own MyDay Dashboard before moving on?
Section 5 — Rendering the task list
This section covers rendering the task list. Rendering the task list clears it and rebuilds it from the visible tasks, creating a list item, a checkbox-style button, text, a priority badge, and a delete button for each task. Rebuilding from state keeps the screen honest.
Thinking about rendering the task list in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat rendering the task list as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through rendering the task list in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with rendering the task list for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When rendering the task list feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects rendering the task list to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
const done = state.tasks.filter(task => task.done).length;
const progress = state.tasks.length ? Math.round(done / state.tasks.length * 100) : 0;
Progress is a simple calculation from the state, not a number typed by hand, so it stays correct as tasks are added and completed.
A common mistake with rendering the task list is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on rendering the task list, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Save after every meaningful change, not only when the page closes, because a closed tab should not lose a finished task.
Check: What is one thing you would check about rendering the task list in your own MyDay Dashboard before moving on?
Section 6 — Rendering the notes list
This section covers rendering the notes list. Rendering notes sorts pinned notes first, then shows each note title, body, a pin button, an edit button, and a delete button. Sorting at render time keeps the stored order simple and the display rule in one place.
Thinking about rendering the notes list in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat rendering the notes list as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through rendering the notes list in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with rendering the notes list for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When rendering the notes list feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects rendering the notes list to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
form.addEventListener('submit', (event) => {
event.preventDefault();
const text = input.value.trim();
if (!text) return;
});
Preventing the default submit stops the page reloading, trimming removes accidental spaces, and an empty value is rejected before any state changes.
A common mistake with rendering the notes list is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on rendering the notes list, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
When a button does nothing, check the wiring first: is the listener attached, is the element selected, and does the handler run at all. Log the state to the console while you build, then remove those logs when the feature works, so the finished code stays clean.
Check: What is one thing you would check about rendering the notes list in your own MyDay Dashboard before moving on?
Section 7 — Rendering the overview counts
This section covers rendering the overview counts. The overview reads the task list and counts totals, completed tasks, and active tasks, then writes those numbers into the panel. Counts are always calculated, never stored separately, so they cannot drift out of date.
Thinking about rendering the overview counts in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat rendering the overview counts as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through rendering the overview counts in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with rendering the overview counts for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When rendering the overview counts feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects rendering the overview counts to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
const state = { tasks: [], notes: [], filter: 'all', query: '' };
One state object holds the whole dashboard, so rendering, filtering and saving all read from the same place instead of from scattered variables.
A common mistake with rendering the overview counts is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on rendering the overview counts, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Log the state to the console while you build, then remove those logs when the feature works, so the finished code stays clean. Treat stored data as untrusted, because a user may have an older version, a cleared store, or a value another tool changed.
Check: What is one thing you would check about rendering the overview counts in your own MyDay Dashboard before moving on?
Section 8 — Adding a task
This section covers adding a task. Adding a task reads the form, trims the text, rejects an empty value, creates a task object with a unique id, and pushes it into the state before saving and re-rendering. Each step is small, and the order matters.
Thinking about adding a task in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat adding a task as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through adding a task in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with adding a task for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When adding a task feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects adding a task to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
localStorage.setItem('myday-data-v1', JSON.stringify(state));
Saving means turning the state into text and storing it under one key, and loading is the reverse: read the text and turn it back into data.
A common mistake with adding a task is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on adding a task, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Treat stored data as untrusted, because a user may have an older version, a cleared store, or a value another tool changed. Filter and search should combine predictably: apply both to the same list and show the count of what remains. Avoid reaching into the document in many scattered places; centralise rendering so one change updates every panel that depends on it.
Check: What is one thing you would check about adding a task in your own MyDay Dashboard before moving on?
Section 9 — Adding a note
This section covers adding a note. Adding a note reads the title and body, trims both, requires at least a title, creates a note object with pinned set to false, and then saves and re-renders. A note without a title would be hard to find later, so it is rejected.
Thinking about adding a note in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat adding a note as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through adding a note in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with adding a note for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When adding a note feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects adding a note to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
function renderTasks() {
taskList.innerHTML = '';
visibleTasks().forEach(task => taskList.append(createTaskItem(task)));
}
Rendering clears the list and rebuilds it from the current visible tasks, which guarantees the screen matches the state after every change.
A common mistake with adding a note is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on adding a note, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Filter and search should combine predictably: apply both to the same list and show the count of what remains. Avoid reaching into the document in many scattered places; centralise rendering so one change updates every panel that depends on it.
Check: What is one thing you would check about adding a note in your own MyDay Dashboard before moving on?
Section 10 — Toggling a task complete
This section covers toggling a task complete. Toggling finds the task by id, flips its done flag, saves, and re-renders, which moves it between filtered views and updates the progress. One flag drives the checkbox, the styling, the filter, and the counts together.
Thinking about toggling a task complete in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat toggling a task complete as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through toggling a task complete in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with toggling a task complete for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When toggling a task complete feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects toggling a task complete to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
taskList.addEventListener('click', (event) => {
const button = event.target.closest('button');
if (!button) return;
});
One listener on the list can handle clicks on any of its buttons, including buttons added later, by checking which button was actually pressed.
A common mistake with toggling a task complete is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on toggling a task complete, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Avoid reaching into the document in many scattered places; centralise rendering so one change updates every panel that depends on it. A small list does not need clever optimisation, but it does need a render that is easy to read and easy to reason about.
Check: What is one thing you would check about toggling a task complete in your own MyDay Dashboard before moving on?
Section 11 — Deleting a task
This section covers deleting a task. Deleting removes the task with the matching id from the array, then saves and re-renders, which also updates the overview and the progress bar. Deletion in this project is immediate, so the button label must make the action clear.
Thinking about deleting a task in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat deleting a task as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through deleting a task in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with deleting a task for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When deleting a task feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects deleting a task to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
const done = state.tasks.filter(task => task.done).length;
const progress = state.tasks.length ? Math.round(done / state.tasks.length * 100) : 0;
Progress is a simple calculation from the state, not a number typed by hand, so it stays correct as tasks are added and completed.
A common mistake with deleting a task is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on deleting a task, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
A small list does not need clever optimisation, but it does need a render that is easy to read and easy to reason about. Name event handlers after the user action, such as add task or toggle task, so the code reads like the behaviour it provides.
Check: What is one thing you would check about deleting a task in your own MyDay Dashboard before moving on?
Section 12 — Deleting a note
This section covers deleting a note. Deleting a note removes it by id, saves, and re-renders, and if the last note is removed the empty state appears. The empty state is itself a render result, not a special case handled by hand.
Thinking about deleting a note in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat deleting a note as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through deleting a note in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with deleting a note for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When deleting a note feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects deleting a note to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
form.addEventListener('submit', (event) => {
event.preventDefault();
const text = input.value.trim();
if (!text) return;
});
Preventing the default submit stops the page reloading, trimming removes accidental spaces, and an empty value is rejected before any state changes.
A common mistake with deleting a note is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on deleting a note, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Name event handlers after the user action, such as add task or toggle task, so the code reads like the behaviour it provides. Test with real actions in order: add, complete, filter, search, reload, and confirm the result survives each step.
Check: What is one thing you would check about deleting a note in your own MyDay Dashboard before moving on?
Section 13 — Editing a note in place
This section covers editing a note in place. Editing a note fills the note form with its title and body, remembers which note is being edited, and on submit updates that note instead of creating a new one. Reusing one form for add and edit keeps the interface small.
Thinking about editing a note in place in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat editing a note in place as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through editing a note in place in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with editing a note in place for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When editing a note in place feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects editing a note in place to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
const state = { tasks: [], notes: [], filter: 'all', query: '' };
One state object holds the whole dashboard, so rendering, filtering and saving all read from the same place instead of from scattered variables.
A common mistake with editing a note in place is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on editing a note in place, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Test with real actions in order: add, complete, filter, search, reload, and confirm the result survives each step.
Check: What is one thing you would check about editing a note in place in your own MyDay Dashboard before moving on?
Section 14 — Pinning a note
This section covers pinning a note. Pinning flips a note's pinned flag, saves, and re-renders, which brings pinned notes to the top of the notes list. Pinning is a display preference stored with the note, not a separate list.
Thinking about pinning a note in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat pinning a note as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through pinning a note in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with pinning a note for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When pinning a note feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects pinning a note to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
localStorage.setItem('myday-data-v1', JSON.stringify(state));
Saving means turning the state into text and storing it under one key, and loading is the reverse: read the text and turn it back into data.
A common mistake with pinning a note is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on pinning a note, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
If two panels disagree, one of them is reading stale data, so trace both back to the same state object. State is the single source of truth: the screen should show what the state contains, and nothing else. Change state first and then re-render, so the display can never drift away from the data it claims to show.
Check: What is one thing you would check about pinning a note in your own MyDay Dashboard before moving on?
Section 15 — Filtering: All, Active, Done
This section covers filtering: all, active, done. Filtering selects tasks by their done flag: All shows everything, Active shows unfinished tasks, and Done shows completed ones. The filter value lives in state, so a reload could restore it, though this project resets it to All.
Thinking about filtering: all, active, done in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat filtering: all, active, done as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through filtering: all, active, done in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with filtering: all, active, done for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When filtering: all, active, done feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects filtering: all, active, done to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
function renderTasks() {
taskList.innerHTML = '';
visibleTasks().forEach(task => taskList.append(createTaskItem(task)));
}
Rendering clears the list and rebuilds it from the current visible tasks, which guarantees the screen matches the state after every change.
A common mistake with filtering: all, active, done is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on filtering: all, active, done, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
State is the single source of truth: the screen should show what the state contains, and nothing else. Change state first and then re-render, so the display can never drift away from the data it claims to show.
Check: What is one thing you would check about filtering: all, active, done in your own MyDay Dashboard before moving on?
Section 16 — Searching tasks and notes
This section covers searching tasks and notes. Searching compares the lowercased query with the lowercased text of each task and note, so capitalisation does not affect results. One query filters both lists, and the overview still counts all tasks, not only visible ones.
Thinking about searching tasks and notes in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat searching tasks and notes as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through searching tasks and notes in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with searching tasks and notes for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When searching tasks and notes feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects searching tasks and notes to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
taskList.addEventListener('click', (event) => {
const button = event.target.closest('button');
if (!button) return;
});
One listener on the list can handle clicks on any of its buttons, including buttons added later, by checking which button was actually pressed.
A common mistake with searching tasks and notes is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on searching tasks and notes, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Change state first and then re-render, so the display can never drift away from the data it claims to show. Keep functions small and named for one job, because a function that adds, saves and renders at once is hard to test and hard to fix.
Check: What is one thing you would check about searching tasks and notes in your own MyDay Dashboard before moving on?
Section 17 — Sorting by priority
This section covers sorting by priority. Tasks are shown with High priority first, then Medium, then Low, using a simple priority order map, while keeping their creation order within each level. Sorting at display time leaves the stored array untouched.
Thinking about sorting by priority in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat sorting by priority as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through sorting by priority in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with sorting by priority for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When sorting by priority feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects sorting by priority to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
const done = state.tasks.filter(task => task.done).length;
const progress = state.tasks.length ? Math.round(done / state.tasks.length * 100) : 0;
Progress is a simple calculation from the state, not a number typed by hand, so it stays correct as tasks are added and completed.
A common mistake with sorting by priority is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on sorting by priority, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Keep functions small and named for one job, because a function that adds, saves and renders at once is hard to test and hard to fix. Handle the empty case deliberately, because a dashboard with no tasks yet is a normal state, not an error.
Check: What is one thing you would check about sorting by priority in your own MyDay Dashboard before moving on?
Section 18 — Calculating progress
This section covers calculating progress. Progress is completed tasks divided by total tasks, times one hundred, rounded, with zero tasks giving zero percent rather than a division error. Guarding the empty case is a habit worth forming in every calculation.
Thinking about calculating progress in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat calculating progress as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through calculating progress in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with calculating progress for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When calculating progress feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects calculating progress to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
form.addEventListener('submit', (event) => {
event.preventDefault();
const text = input.value.trim();
if (!text) return;
});
Preventing the default submit stops the page reloading, trimming removes accidental spaces, and an empty value is rejected before any state changes.
A common mistake with calculating progress is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on calculating progress, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Handle the empty case deliberately, because a dashboard with no tasks yet is a normal state, not an error. Validate input at the point of entry and give a plain message, so the user learns what to fix without losing what they typed. Save after every meaningful change, not only when the page closes, because a closed tab should not lose a finished task.
Check: What is one thing you would check about calculating progress in your own MyDay Dashboard before moving on?
Section 19 — Building the bar display data
This section covers building the bar display data. The bar display counts tasks per priority, finds the largest count, and sizes each bar relative to that largest count, with counts shown as text beside each bar. Relative sizing keeps the display meaningful for both small and large lists.
Thinking about building the bar display data in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat building the bar display data as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through building the bar display data in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with building the bar display data for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When building the bar display data feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects building the bar display data to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
const state = { tasks: [], notes: [], filter: 'all', query: '' };
One state object holds the whole dashboard, so rendering, filtering and saving all read from the same place instead of from scattered variables.
A common mistake with building the bar display data is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on building the bar display data, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Validate input at the point of entry and give a plain message, so the user learns what to fix without losing what they typed.
Check: What is one thing you would check about building the bar display data in your own MyDay Dashboard before moving on?
Section 20 — Showing validation messages
This section covers showing validation messages. When a form is submitted empty, a short message appears near the form explaining what is missing, instead of silently doing nothing. A message respects the user's time: it says what went wrong and what to do.
Thinking about showing validation messages in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat showing validation messages as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through showing validation messages in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with showing validation messages for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When showing validation messages feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects showing validation messages to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
localStorage.setItem('myday-data-v1', JSON.stringify(state));
Saving means turning the state into text and storing it under one key, and loading is the reverse: read the text and turn it back into data.
A common mistake with showing validation messages is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on showing validation messages, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Save after every meaningful change, not only when the page closes, because a closed tab should not lose a finished task. When a button does nothing, check the wiring first: is the listener attached, is the element selected, and does the handler run at all.
Check: What is one thing you would check about showing validation messages in your own MyDay Dashboard before moving on?
Section 21 — Preventing empty submissions
This section covers preventing empty submissions. Empty submissions are prevented by trimming the input and checking the result before any state change, with the required attribute as a first line of defence. Two layers, markup and script, are better than either alone.
Thinking about preventing empty submissions in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat preventing empty submissions as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through preventing empty submissions in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with preventing empty submissions for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When preventing empty submissions feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects preventing empty submissions to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
function renderTasks() {
taskList.innerHTML = '';
visibleTasks().forEach(task => taskList.append(createTaskItem(task)));
}
Rendering clears the list and rebuilds it from the current visible tasks, which guarantees the screen matches the state after every change.
A common mistake with preventing empty submissions is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on preventing empty submissions, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
When a button does nothing, check the wiring first: is the listener attached, is the element selected, and does the handler run at all. Log the state to the console while you build, then remove those logs when the feature works, so the finished code stays clean.
Check: What is one thing you would check about preventing empty submissions in your own MyDay Dashboard before moving on?
Section 22 — Event delegation for lists
This section covers event delegation for lists. One click listener on each list handles buttons inside it, using the closest method to find the button that was pressed and a data attribute to find the item id. Delegation works for items added later, which individual listeners would miss.
Thinking about event delegation for lists in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat event delegation for lists as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through event delegation for lists in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with event delegation for lists for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When event delegation for lists feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects event delegation for lists to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
taskList.addEventListener('click', (event) => {
const button = event.target.closest('button');
if (!button) return;
});
One listener on the list can handle clicks on any of its buttons, including buttons added later, by checking which button was actually pressed.
A common mistake with event delegation for lists is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on event delegation for lists, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Log the state to the console while you build, then remove those logs when the feature works, so the finished code stays clean. Treat stored data as untrusted, because a user may have an older version, a cleared store, or a value another tool changed.
Check: What is one thing you would check about event delegation for lists in your own MyDay Dashboard before moving on?
Section 23 — Keeping the screen and state in sync
This section covers keeping the screen and state in sync. After every state change the code saves and then re-renders all affected panels, so no panel shows an older version of the data. A single update path, used everywhere, prevents the classic bug of two panels disagreeing.
Thinking about keeping the screen and state in sync in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat keeping the screen and state in sync as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through keeping the screen and state in sync in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with keeping the screen and state in sync for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When keeping the screen and state in sync feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects keeping the screen and state in sync to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
const done = state.tasks.filter(task => task.done).length;
const progress = state.tasks.length ? Math.round(done / state.tasks.length * 100) : 0;
Progress is a simple calculation from the state, not a number typed by hand, so it stays correct as tasks are added and completed.
A common mistake with keeping the screen and state in sync is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on keeping the screen and state in sync, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Check: What is one thing you would check about keeping the screen and state in sync in your own MyDay Dashboard before moving on?
Section 24 — Unique ids for tasks and notes
This section covers unique ids for tasks and notes. Each item gets an id built from the current time plus a counter, which is unique enough for a personal dashboard without any library. Unique ids are what let toggle, edit, and delete find exactly one item.
Thinking about unique ids for tasks and notes in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat unique ids for tasks and notes as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through unique ids for tasks and notes in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with unique ids for tasks and notes for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When unique ids for tasks and notes feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects unique ids for tasks and notes to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
form.addEventListener('submit', (event) => {
event.preventDefault();
const text = input.value.trim();
if (!text) return;
});
Preventing the default submit stops the page reloading, trimming removes accidental spaces, and an empty value is rejected before any state changes.
A common mistake with unique ids for tasks and notes is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on unique ids for tasks and notes, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Filter and search should combine predictably: apply both to the same list and show the count of what remains.
Check: What is one thing you would check about unique ids for tasks and notes in your own MyDay Dashboard before moving on?
Section 25 — Showing created dates
This section covers showing created dates. Each task stores a created timestamp, and rendering shows it as a short, readable date beside the task. Dates are stored as numbers and formatted only at display time, which keeps the stored data clean.
Thinking about showing created dates in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat showing created dates as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through showing created dates in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with showing created dates for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When showing created dates feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects showing created dates to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
const state = { tasks: [], notes: [], filter: 'all', query: '' };
One state object holds the whole dashboard, so rendering, filtering and saving all read from the same place instead of from scattered variables.
A common mistake with showing created dates is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on showing created dates, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Avoid reaching into the document in many scattered places; centralise rendering so one change updates every panel that depends on it. A small list does not need clever optimisation, but it does need a render that is easy to read and easy to reason about.
Check: What is one thing you would check about showing created dates in your own MyDay Dashboard before moving on?
Section 26 — Clearing completed tasks
This section covers clearing completed tasks. A clear-completed button removes every task whose done flag is true, then saves and re-renders, leaving active tasks untouched. Bulk actions deserve a clear label, because their effect is wider than a single delete.
Thinking about clearing completed tasks in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat clearing completed tasks as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through clearing completed tasks in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with clearing completed tasks for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When clearing completed tasks feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects clearing completed tasks to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
localStorage.setItem('myday-data-v1', JSON.stringify(state));
Saving means turning the state into text and storing it under one key, and loading is the reverse: read the text and turn it back into data.
A common mistake with clearing completed tasks is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on clearing completed tasks, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
A small list does not need clever optimisation, but it does need a render that is easy to read and easy to reason about. Name event handlers after the user action, such as add task or toggle task, so the code reads like the behaviour it provides.
Check: What is one thing you would check about clearing completed tasks in your own MyDay Dashboard before moving on?
Section 27 — Confirming a destructive action
This section covers confirming a destructive action. Before clearing completed tasks, the dashboard asks for confirmation with a simple inline confirm step on the button itself, rather than deleting silently. A confirm step is cheap insurance against a mistaken click.
Thinking about confirming a destructive action in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat confirming a destructive action as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through confirming a destructive action in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with confirming a destructive action for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When confirming a destructive action feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects confirming a destructive action to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
function renderTasks() {
taskList.innerHTML = '';
visibleTasks().forEach(task => taskList.append(createTaskItem(task)));
}
Rendering clears the list and rebuilds it from the current visible tasks, which guarantees the screen matches the state after every change.
A common mistake with confirming a destructive action is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on confirming a destructive action, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Name event handlers after the user action, such as add task or toggle task, so the code reads like the behaviour it provides. Test with real actions in order: add, complete, filter, search, reload, and confirm the result survives each step.
Check: What is one thing you would check about confirming a destructive action in your own MyDay Dashboard before moving on?
Section 28 — Keyboard: Enter submits a form
This section covers keyboard: enter submits a form. Because add-task and add-note are real forms with submit buttons, pressing Enter in a field submits the form, which the handler then processes. Native form behaviour is free accessibility and free keyboard support.
Thinking about keyboard: enter submits a form in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat keyboard: enter submits a form as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through keyboard: enter submits a form in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with keyboard: enter submits a form for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When keyboard: enter submits a form feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects keyboard: enter submits a form to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
taskList.addEventListener('click', (event) => {
const button = event.target.closest('button');
if (!button) return;
});
One listener on the list can handle clicks on any of its buttons, including buttons added later, by checking which button was actually pressed.
A common mistake with keyboard: enter submits a form is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on keyboard: enter submits a form, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Test with real actions in order: add, complete, filter, search, reload, and confirm the result survives each step. If two panels disagree, one of them is reading stale data, so trace both back to the same state object.
Check: What is one thing you would check about keyboard: enter submits a form in your own MyDay Dashboard before moving on?
Section 29 — Focus after adding an item
This section covers focus after adding an item. After a task or note is added, focus returns to the first field of the form, so adding several items in a row needs no mouse movement. Small focus decisions make a repeated task feel fast instead of fiddly.
Thinking about focus after adding an item in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat focus after adding an item as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through focus after adding an item in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with focus after adding an item for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When focus after adding an item feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects focus after adding an item to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
const done = state.tasks.filter(task => task.done).length;
const progress = state.tasks.length ? Math.round(done / state.tasks.length * 100) : 0;
Progress is a simple calculation from the state, not a number typed by hand, so it stays correct as tasks are added and completed.
A common mistake with focus after adding an item is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on focus after adding an item, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
If two panels disagree, one of them is reading stale data, so trace both back to the same state object.
Check: What is one thing you would check about focus after adding an item in your own MyDay Dashboard before moving on?
Section 30 — Updating empty states
This section covers updating empty states. After every render, each list checks whether it has visible items and shows or hides its empty message accordingly. An empty message after filtering is different from an empty list, so the wording says what is filtered.
Thinking about updating empty states in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat updating empty states as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through updating empty states in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with updating empty states for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When updating empty states feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects updating empty states to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
form.addEventListener('submit', (event) => {
event.preventDefault();
const text = input.value.trim();
if (!text) return;
});
Preventing the default submit stops the page reloading, trimming removes accidental spaces, and an empty value is rejected before any state changes.
A common mistake with updating empty states is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on updating empty states, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
State is the single source of truth: the screen should show what the state contains, and nothing else. Change state first and then re-render, so the display can never drift away from the data it claims to show.
Check: What is one thing you would check about updating empty states in your own MyDay Dashboard before moving on?
Section 31 — Handling storage errors
This section covers handling storage errors. Saving is wrapped in a try and catch, so if storage is full or unavailable the dashboard still works for the session and shows a plain message. A dashboard that crashes on a storage error has failed at its most basic job.
Thinking about handling storage errors in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat handling storage errors as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through handling storage errors in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with handling storage errors for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When handling storage errors feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects handling storage errors to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
const state = { tasks: [], notes: [], filter: 'all', query: '' };
One state object holds the whole dashboard, so rendering, filtering and saving all read from the same place instead of from scattered variables.
A common mistake with handling storage errors is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on handling storage errors, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Change state first and then re-render, so the display can never drift away from the data it claims to show. Keep functions small and named for one job, because a function that adds, saves and renders at once is hard to test and hard to fix.
Check: What is one thing you would check about handling storage errors in your own MyDay Dashboard before moving on?
Section 32 — Versioning the stored data
This section covers versioning the stored data. The storage key includes a version, myday-data-v1, so a future change to the data shape can use a new key or migrate old data deliberately. Versioning is forward planning that costs almost nothing now.
Thinking about versioning the stored data in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat versioning the stored data as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through versioning the stored data in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with versioning the stored data for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When versioning the stored data feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects versioning the stored data to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
localStorage.setItem('myday-data-v1', JSON.stringify(state));
Saving means turning the state into text and storing it under one key, and loading is the reverse: read the text and turn it back into data.
A common mistake with versioning the stored data is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on versioning the stored data, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Keep functions small and named for one job, because a function that adds, saves and renders at once is hard to test and hard to fix. Handle the empty case deliberately, because a dashboard with no tasks yet is a normal state, not an error.
Check: What is one thing you would check about versioning the stored data in your own MyDay Dashboard before moving on?
Section 33 — Exporting data as a file
This section covers exporting data as a file. Export creates a JSON file from the state and offers it as a download, so the user can keep a copy of their tasks and notes. Export is read-only: it changes nothing in the dashboard itself.
Thinking about exporting data as a file in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat exporting data as a file as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through exporting data as a file in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with exporting data as a file for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When exporting data as a file feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects exporting data as a file to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
function renderTasks() {
taskList.innerHTML = '';
visibleTasks().forEach(task => taskList.append(createTaskItem(task)));
}
Rendering clears the list and rebuilds it from the current visible tasks, which guarantees the screen matches the state after every change.
A common mistake with exporting data as a file is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on exporting data as a file, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Handle the empty case deliberately, because a dashboard with no tasks yet is a normal state, not an error. Validate input at the point of entry and give a plain message, so the user learns what to fix without losing what they typed.
Check: What is one thing you would check about exporting data as a file in your own MyDay Dashboard before moving on?
Section 34 — Counting tasks by priority
This section covers counting tasks by priority. Counting by priority filters the task array three times, once per level, and stores the three numbers for the overview and the bar display. Simple, readable counting beats a clever one-liner nobody can debug.
Thinking about counting tasks by priority in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat counting tasks by priority as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through counting tasks by priority in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with counting tasks by priority for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When counting tasks by priority feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects counting tasks by priority to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
taskList.addEventListener('click', (event) => {
const button = event.target.closest('button');
if (!button) return;
});
One listener on the list can handle clicks on any of its buttons, including buttons added later, by checking which button was actually pressed.
A common mistake with counting tasks by priority is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on counting tasks by priority, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Validate input at the point of entry and give a plain message, so the user learns what to fix without losing what they typed. Save after every meaningful change, not only when the page closes, because a closed tab should not lose a finished task.
Check: What is one thing you would check about counting tasks by priority in your own MyDay Dashboard before moving on?
Section 35 — Updating the progress bar width
This section covers updating the progress bar width. The progress bar width is set from the calculated percentage, and the same percentage is written as text inside or beside the bar. Setting both together keeps the visual and the text in agreement.
Thinking about updating the progress bar width in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat updating the progress bar width as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through updating the progress bar width in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with updating the progress bar width for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When updating the progress bar width feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects updating the progress bar width to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
const done = state.tasks.filter(task => task.done).length;
const progress = state.tasks.length ? Math.round(done / state.tasks.length * 100) : 0;
Progress is a simple calculation from the state, not a number typed by hand, so it stays correct as tasks are added and completed.
A common mistake with updating the progress bar width is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on updating the progress bar width, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Save after every meaningful change, not only when the page closes, because a closed tab should not lose a finished task.
Check: What is one thing you would check about updating the progress bar width in your own MyDay Dashboard before moving on?
Section 36 — Combining filter and search
This section covers combining filter and search. Visible tasks are those that pass the filter and match the search query, applied in that order to the same array. Combining two rules in one function makes the result predictable and easy to test.
Thinking about combining filter and search in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat combining filter and search as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through combining filter and search in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with combining filter and search for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When combining filter and search feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects combining filter and search to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
form.addEventListener('submit', (event) => {
event.preventDefault();
const text = input.value.trim();
if (!text) return;
});
Preventing the default submit stops the page reloading, trimming removes accidental spaces, and an empty value is rejected before any state changes.
A common mistake with combining filter and search is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on combining filter and search, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
When a button does nothing, check the wiring first: is the listener attached, is the element selected, and does the handler run at all. Log the state to the console while you build, then remove those logs when the feature works, so the finished code stays clean.
Check: What is one thing you would check about combining filter and search in your own MyDay Dashboard before moving on?
Section 37 — Why no debounce is needed here
This section covers why no debounce is needed here. Typing in the search box re-renders immediately, which is fine for a small personal list, so no debounce delay is added. Adding a delay would be optimisation for a problem this project does not have.
Thinking about why no debounce is needed here in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat why no debounce is needed here as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through why no debounce is needed here in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with why no debounce is needed here for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When why no debounce is needed here feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects why no debounce is needed here to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
const state = { tasks: [], notes: [], filter: 'all', query: '' };
One state object holds the whole dashboard, so rendering, filtering and saving all read from the same place instead of from scattered variables.
A common mistake with why no debounce is needed here is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on why no debounce is needed here, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Log the state to the console while you build, then remove those logs when the feature works, so the finished code stays clean.
Check: What is one thing you would check about why no debounce is needed here in your own MyDay Dashboard before moving on?
Section 38 — Avoiding duplicate renders
This section covers avoiding duplicate renders. Rendering is triggered once per user action, after the state change, not once per changed panel and not inside a loop. One render per action keeps the code predictable and the screen flicker-free.
Thinking about avoiding duplicate renders in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat avoiding duplicate renders as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through avoiding duplicate renders in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with avoiding duplicate renders for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When avoiding duplicate renders feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects avoiding duplicate renders to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
localStorage.setItem('myday-data-v1', JSON.stringify(state));
Saving means turning the state into text and storing it under one key, and loading is the reverse: read the text and turn it back into data.
A common mistake with avoiding duplicate renders is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on avoiding duplicate renders, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Treat stored data as untrusted, because a user may have an older version, a cleared store, or a value another tool changed. Filter and search should combine predictably: apply both to the same list and show the count of what remains. Avoid reaching into the document in many scattered places; centralise rendering so one change updates every panel that depends on it.
Check: What is one thing you would check about avoiding duplicate renders in your own MyDay Dashboard before moving on?
Section 39 — Separating render functions
This section covers separating render functions. Separate render functions exist for tasks, notes, and the overview, all called by one update function, so a change to one panel does not require editing the others. Separation is what makes a growing file stay manageable.
Thinking about separating render functions in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat separating render functions as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through separating render functions in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with separating render functions for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When separating render functions feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects separating render functions to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
function renderTasks() {
taskList.innerHTML = '';
visibleTasks().forEach(task => taskList.append(createTaskItem(task)));
}
Rendering clears the list and rebuilds it from the current visible tasks, which guarantees the screen matches the state after every change.
A common mistake with separating render functions is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on separating render functions, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Filter and search should combine predictably: apply both to the same list and show the count of what remains. Avoid reaching into the document in many scattered places; centralise rendering so one change updates every panel that depends on it. A small list does not need clever optimisation, but it does need a render that is easy to read and easy to reason about.
Check: What is one thing you would check about separating render functions in your own MyDay Dashboard before moving on?
Section 40 — Small pure helper functions
This section covers small pure helper functions. Helpers such as visible tasks, task counts, and progress percentage take data in and return a result, without touching the document or storage. Pure helpers are the easiest code to test, because they have no hidden effects.
Thinking about small pure helper functions in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat small pure helper functions as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through small pure helper functions in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with small pure helper functions for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When small pure helper functions feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects small pure helper functions to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
taskList.addEventListener('click', (event) => {
const button = event.target.closest('button');
if (!button) return;
});
One listener on the list can handle clicks on any of its buttons, including buttons added later, by checking which button was actually pressed.
A common mistake with small pure helper functions is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on small pure helper functions, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Avoid reaching into the document in many scattered places; centralise rendering so one change updates every panel that depends on it. A small list does not need clever optimisation, but it does need a render that is easy to read and easy to reason about.
Check: What is one thing you would check about small pure helper functions in your own MyDay Dashboard before moving on?
Section 41 — Testing in the console
This section covers testing in the console. During development, logging the state after an action lets you confirm that the data changed as expected before you trust the screen. The console is a diagnostic tool, not a feature, and its logs are removed at the end.
Thinking about testing in the console in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat testing in the console as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through testing in the console in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with testing in the console for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When testing in the console feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects testing in the console to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
const done = state.tasks.filter(task => task.done).length;
const progress = state.tasks.length ? Math.round(done / state.tasks.length * 100) : 0;
Progress is a simple calculation from the state, not a number typed by hand, so it stays correct as tasks are added and completed.
A common mistake with testing in the console is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on testing in the console, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
A small list does not need clever optimisation, but it does need a render that is easy to read and easy to reason about.
Check: What is one thing you would check about testing in the console in your own MyDay Dashboard before moving on?
Section 42 — Debugging with developer tools
This section covers debugging with developer tools. When a feature fails, developer tools show console errors, let you inspect the live list, and let you set breakpoints in the script. Reading the actual error message usually points at the exact line to fix.
Thinking about debugging with developer tools in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat debugging with developer tools as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through debugging with developer tools in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with debugging with developer tools for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When debugging with developer tools feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects debugging with developer tools to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
form.addEventListener('submit', (event) => {
event.preventDefault();
const text = input.value.trim();
if (!text) return;
});
Preventing the default submit stops the page reloading, trimming removes accidental spaces, and an empty value is rejected before any state changes.
A common mistake with debugging with developer tools is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on debugging with developer tools, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Name event handlers after the user action, such as add task or toggle task, so the code reads like the behaviour it provides. Test with real actions in order: add, complete, filter, search, reload, and confirm the result survives each step.
Check: What is one thing you would check about debugging with developer tools in your own MyDay Dashboard before moving on?
Section 43 — Handling corrupted stored data
This section covers handling corrupted stored data. If stored text cannot be parsed, or the parsed value lacks tasks and notes arrays, loading falls back to the seed data and the dashboard keeps working. A fallback turns a potential crash into a fresh start.
Thinking about handling corrupted stored data in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat handling corrupted stored data as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through handling corrupted stored data in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with handling corrupted stored data for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When handling corrupted stored data feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects handling corrupted stored data to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
const state = { tasks: [], notes: [], filter: 'all', query: '' };
One state object holds the whole dashboard, so rendering, filtering and saving all read from the same place instead of from scattered variables.
A common mistake with handling corrupted stored data is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on handling corrupted stored data, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Test with real actions in order: add, complete, filter, search, reload, and confirm the result survives each step. If two panels disagree, one of them is reading stale data, so trace both back to the same state object.
Check: What is one thing you would check about handling corrupted stored data in your own MyDay Dashboard before moving on?
Section 44 — Resetting to demo data
This section covers resetting to demo data. A reset button restores the generic seed data, after confirmation, which is useful for demonstrating the dashboard or recovering from a messy test. Reset is a development and demo aid, not a daily feature, so it sits in the footer.
Thinking about resetting to demo data in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat resetting to demo data as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through resetting to demo data in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with resetting to demo data for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When resetting to demo data feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects resetting to demo data to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
localStorage.setItem('myday-data-v1', JSON.stringify(state));
Saving means turning the state into text and storing it under one key, and loading is the reverse: read the text and turn it back into data.
A common mistake with resetting to demo data is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on resetting to demo data, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
If two panels disagree, one of them is reading stale data, so trace both back to the same state object. State is the single source of truth: the screen should show what the state contains, and nothing else.
Check: What is one thing you would check about resetting to demo data in your own MyDay Dashboard before moving on?
Section 45 — Announcing changes with aria-live
This section covers announcing changes with aria-live. The overview counts and the status line sit in a polite live region, so screen reader users hear updated counts without the page shouting every keystroke. Live regions should announce results, not every intermediate step.
Thinking about announcing changes with aria-live in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat announcing changes with aria-live as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through announcing changes with aria-live in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with announcing changes with aria-live for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When announcing changes with aria-live feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects announcing changes with aria-live to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
function renderTasks() {
taskList.innerHTML = '';
visibleTasks().forEach(task => taskList.append(createTaskItem(task)));
}
Rendering clears the list and rebuilds it from the current visible tasks, which guarantees the screen matches the state after every change.
A common mistake with announcing changes with aria-live is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on announcing changes with aria-live, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
State is the single source of truth: the screen should show what the state contains, and nothing else. Change state first and then re-render, so the display can never drift away from the data it claims to show.
Check: What is one thing you would check about announcing changes with aria-live in your own MyDay Dashboard before moving on?
Section 46 — Keyboard accessibility for list buttons
This section covers keyboard accessibility for list buttons. List buttons are real button elements, so they are focusable and activatable with Enter and Space without extra code. Using real buttons is the simplest accessibility decision in the whole project.
Thinking about keyboard accessibility for list buttons in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat keyboard accessibility for list buttons as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through keyboard accessibility for list buttons in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with keyboard accessibility for list buttons for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When keyboard accessibility for list buttons feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects keyboard accessibility for list buttons to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
taskList.addEventListener('click', (event) => {
const button = event.target.closest('button');
if (!button) return;
});
One listener on the list can handle clicks on any of its buttons, including buttons added later, by checking which button was actually pressed.
A common mistake with keyboard accessibility for list buttons is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on keyboard accessibility for list buttons, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Change state first and then re-render, so the display can never drift away from the data it claims to show. Keep functions small and named for one job, because a function that adds, saves and renders at once is hard to test and hard to fix.
Check: What is one thing you would check about keyboard accessibility for list buttons in your own MyDay Dashboard before moving on?
Section 47 — Performance on a small list
This section covers performance on a small list. Rebuilding small lists on each action is fast enough here, because the dashboard holds tens of items, not thousands. Choosing the simple approach deliberately, and knowing its limit, is good engineering judgement.
Thinking about performance on a small list in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat performance on a small list as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through performance on a small list in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with performance on a small list for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When performance on a small list feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects performance on a small list to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
const done = state.tasks.filter(task => task.done).length;
const progress = state.tasks.length ? Math.round(done / state.tasks.length * 100) : 0;
Progress is a simple calculation from the state, not a number typed by hand, so it stays correct as tasks are added and completed.
A common mistake with performance on a small list is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on performance on a small list, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Keep functions small and named for one job, because a function that adds, saves and renders at once is hard to test and hard to fix.
Check: What is one thing you would check about performance on a small list in your own MyDay Dashboard before moving on?
Section 48 — Organising app.js
This section covers organising app.js. The script is organised in order: state, storage, helpers, rendering, event handlers, and startup, with short comments marking each part. A reader should be able to find any behaviour by its section, not by searching the whole file.
Thinking about organising app.js in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat organising app.js as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through organising app.js in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with organising app.js for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When organising app.js feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects organising app.js to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
form.addEventListener('submit', (event) => {
event.preventDefault();
const text = input.value.trim();
if (!text) return;
});
Preventing the default submit stops the page reloading, trimming removes accidental spaces, and an empty value is rejected before any state changes.
A common mistake with organising app.js is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on organising app.js, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Handle the empty case deliberately, because a dashboard with no tasks yet is a normal state, not an error. Validate input at the point of entry and give a plain message, so the user learns what to fix without losing what they typed. Save after every meaningful change, not only when the page closes, because a closed tab should not lose a finished task.
Check: What is one thing you would check about organising app.js in your own MyDay Dashboard before moving on?
Section 49 — Startup: loading then rendering
This section covers startup: loading then rendering. Startup runs in a fixed order: load stored data or fall back to seed data, attach event listeners, and then render tasks, notes, and the overview once. A fixed startup order prevents the classic first-load bug where the screen renders before the data arrives, or listeners are attached to elements that do not yet exist.
Thinking about startup: loading then rendering in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat startup: loading then rendering as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through startup: loading then rendering in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with startup: loading then rendering for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When startup: loading then rendering feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects startup: loading then rendering to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
const state = { tasks: [], notes: [], filter: 'all', query: '' };
One state object holds the whole dashboard, so rendering, filtering and saving all read from the same place instead of from scattered variables.
A common mistake with startup: loading then rendering is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on startup: loading then rendering, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Validate input at the point of entry and give a plain message, so the user learns what to fix without losing what they typed.
Check: What is one thing you would check about startup: loading then rendering in your own MyDay Dashboard before moving on?
Section 50 — Chapter checkpoint: behaviour and data done
This section covers chapter checkpoint: behaviour and data done. By the end of this chapter the dashboard should be fully usable: add, complete, delete, edit, pin, filter, search, and reload, with data surviving a refresh. A working dashboard with plain styling would already be a success; this one also looks good.
Thinking about chapter checkpoint: behaviour and data done in the MyDay Dashboard helps to keep the work concrete, because every decision can be tested against a real panel, a real list, or a real button.
Beginners often treat chapter checkpoint: behaviour and data done as a finishing touch, but in this dashboard it shapes how the user finds, changes, and trusts their own tasks and notes.
Work through chapter checkpoint: behaviour and data done in small steps: make one change, open the page, try the feature with the keyboard and the mouse, and only then move on.
A useful habit is to ask what could go wrong with chapter checkpoint: behaviour and data done for a first-time visitor, a hurried visitor, and a visitor on a small phone screen.
When chapter checkpoint: behaviour and data done feels confusing, simplify the surface first and keep the underlying idea the same, because complexity in the interface rarely helps the user.
Good front-end work connects chapter checkpoint: behaviour and data done to the rest of the project, so a change here should not silently break a filter, a count, or a saved list elsewhere.
Here is a short example from the MyDay Dashboard:
localStorage.setItem('myday-data-v1', JSON.stringify(state));
Saving means turning the state into text and storing it under one key, and loading is the reverse: read the text and turn it back into data.
A common mistake with chapter checkpoint: behaviour and data done is to rush it, add it everywhere at once, and then struggle to find which change broke the page. Work on one panel at a time, keep a working version saved, and test the dashboard after each step, including reloading the page to confirm that saved tasks and notes are still there. If something looks wrong, undo the last change and re-read the code around it before trying a different fix, because a calm, narrow check usually finds the problem faster than rewriting a whole file.
To check your own work on chapter checkpoint: behaviour and data done, open the dashboard, use the feature as a visitor would, and look for three things: does it do the job, does it still work after a reload, and does it behave sensibly at a narrow width and with the keyboard alone. Write down anything that fails, fix one item at a time, and re-test the whole flow after each fix, because a fix in one panel can affect a count, a filter, or a saved list in another.
Save after every meaningful change, not only when the page closes, because a closed tab should not lose a finished task.
Check: What is one thing you would check about chapter checkpoint: behaviour and data done in your own MyDay Dashboard before moving on?
Practical task
Make MyDay Dashboard work: write app.js with one state object, localStorage saving under myday-data-v1, rendering for tasks, notes, and the overview, and handlers for adding, completing, deleting, editing, pinning, filtering, and searching. Test the full flow in order: add a task, add a note, complete the task, filter to Done, search, reload the page, and confirm the data survives. Then test the empty states, the progress calculation with zero tasks, and corrupted stored data by clearing storage, and fix any failure before moving on.
Chapter questions
- What is in the MyDay Dashboard state object, and why is it the single source of truth?
- Explain, step by step, what happens when a user adds a task, from the form submit to the screen updating.
- Why does rendering rebuild lists from state instead of editing individual elements in place?
- How does the dashboard handle corrupted stored data, and why is a fallback better than a crash?
- How do filtering and searching combine, and what does the overview count in each case?