What you'll learn
Quick Answer
Begin with DOM manipulation and events using a counter, tip calculator and quiz, then move to projects that fetch data from an API, then ones managing real state such as a to-do list with localStorage or a shopping cart. Ten are listed below with what each teaches and how to extend it. Build them with plain JavaScript before a framework, because frameworks assume you already understand the DOM and events they abstract.
Four Projects for DOM and Events
These need no build tools — an HTML file, a CSS file and a JS file.
1. Counter with increment, decrement and reset. Trivial-looking and genuinely useful: it is the smallest complete loop of state, event, re-render. Teaches querySelector, addEventListener and updating text content. Stretch: a step size input and a minimum bound.
2. Tip and bill splitter. Enter a bill, tip percentage and number of people; show the split. Teaches reading input values, number conversion, and formatting currency with toLocaleString. Stretch: handle the empty-input case, which is where Number('') quietly becomes zero.
3. Quiz app. Questions from an array, one at a time, with a score at the end. Teaches arrays of objects, rendering from data, and tracking state across steps. Stretch: a timer per question, and shuffling the options.
4. Accordion or tabbed interface. Teaches class toggling, event delegation and the accessibility attributes that most tutorials omit — aria-expanded and keyboard support. Stretch: make it fully keyboard navigable, which is a genuine differentiator.
Project 4 is worth taking seriously. Very few fresher portfolios show any awareness of accessibility, and interviewers notice.
Three Projects for Async and APIs
Now the data comes from somewhere else, which introduces the states tutorials skip.
5. Weather app. Enter a city, fetch the forecast, display it. Teaches fetch, promises, async/await, and reading API documentation. Stretch: handle the three states properly — loading, error, and empty — because real users hit all of them.
6. GitHub profile finder. Enter a username, show avatar, repository count and top repositories. Teaches working with nested JSON, rendering lists, and rate limits. Stretch: debounce the input so you do not fire a request per keystroke.
7. Movie or recipe search. Search a public API and display results in cards. Teaches query parameters, pagination and image handling. Stretch: a favourites list saved to localStorage, which combines async data with persistence.
The lesson these three actually teach is that the happy path is the easy part. Showing a spinner, handling a failed request, and telling the user when nothing matched is most of the work, and it is exactly what separates a real app from a demo.
try {
setLoading(true);
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}`); // fetch does NOT throw on 404
render(await res.json());
} catch (err) {
showError(err.message);
} finally {
setLoading(false);
}
Three Projects That Manage Real State
These are large enough to teach structure, and they are the ones worth showing.
8. To-do list with localStorage. The canonical project, and still a good one if you do it properly. Teaches array manipulation, event delegation for dynamically added items, and persistence. Stretch: filter by status, edit in place, drag to reorder, and handle the storage quota being full.
9. Shopping cart. Add items, change quantities, remove, show a running total. Teaches deriving state rather than storing it — the total should be computed from the items, never kept as a separate variable that can drift out of sync. Stretch: persist the cart, and apply a discount rule.
10. Expense tracker with charts. Add income and expenses by category, show balance and a breakdown. Teaches reducing arrays to summaries, date handling and a charting library. Stretch: filter by month and export to CSV.
Project 9 teaches the most transferable idea on this list. Storing a total alongside the items means two sources of truth that can disagree; computing it on render means they cannot. That principle is the entire basis of how React and every state library works.
Build These in Plain JavaScript First
There is a strong temptation to jump straight to React. Resist it for these projects, for a specific reason.
React abstracts the DOM, event handling and re-rendering. If you have never done those manually, the abstraction hides machinery you do not yet understand — which is why so many people can build a React app but cannot debug one.
Building a to-do list with plain JavaScript teaches you why you need to re-render after every change, why event delegation exists for dynamic lists, and why keeping the DOM and your data in sync by hand is tedious. Then React's value is obvious rather than assumed.
Two habits to carry into these projects:
- Keep data and display separate. Hold an array of items, and write one
render()function that draws the whole list from it. Do not read state back out of the DOM. - Use event delegation for dynamic content. One listener on the container, checking
event.target, rather than attaching a listener to every item you create.
list.addEventListener('click', e => {
if (e.target.matches('.delete')) {
items = items.filter(i => i.id !== +e.target.dataset.id);
render();
}
});Once three of these are comfortable, rebuild one in React. The comparison teaches more than either version alone.
Making Them Count
Deploy them. Static sites host free on several platforms and take minutes. A live link is what a recruiter clicks; a repository is what they might read afterwards.
Make them work on a phone. Most people who open your link will be on mobile. A layout that breaks below 400px undoes the impression instantly, and responsive CSS is a skill worth proving.
Write the README. What it does, a screenshot or short recording, how to run it locally, and what you would improve. The last part signals self-awareness, which interviewers read as maturity.
Handle the empty state. What does the to-do list look like with no tasks? A blank screen suggests you never considered it. A short line of guidance suggests you thought about the user.
Do not build ten of these. Build three properly. Ten shallow projects tell an interviewer you can follow instructions; three deep ones give you something to talk about for twenty minutes, which is what actually happens in the room.
