JavaScript projects for beginners and beyond: 13 ideas, each with a first version and a stretch goal
The best JavaScript projects for beginners are small browser apps with visible results: a memory game, a regex tester, a countdown with a shareable link, a to-do list with undo. Each one teaches a different core idea, such as DOM events, state, dates or async requests. Once those feel easy, move to a drag-and-drop board, a canvas game or a tiny test framework. Below are 13 projects in three levels, each with a stack, the concepts it teaches, a first version, a stretch goal and a time estimate.
What JavaScript projects should a beginner build?
Build projects where the browser gives you instant feedback and where one concept does most of the work. A memory game is about state. A regex tester is about errors and escaping. A countdown is about dates. If you pick a project because it looks good on a résumé, you tend to stall on the part that teaches nothing. Pick it for the concept.
Every project below runs in a plain HTML file with no framework and no build step, except the last four, which add Node or a file picker. That is deliberate. Frameworks hide the DOM, and you want to see it at least twice before something hides it. If you already know the basics and want React next, the React project ideas page picks up where this one stops.
| If you want to learn | Build | Level |
|---|---|---|
| State and DOM events | Memory match game | Beginner |
| Error handling and escaping untrusted text | Live regex tester | Beginner |
| Dates, time zones and URLs as input | Countdown with a shareable link | Beginner |
| Immutable data and history | To-do list with undo and redo | Beginner |
| Fetch, caching and number formatting | Currency converter | Beginner |
| Async races and cancelling requests | Search-as-you-type for Wikipedia | Intermediate |
| Browser drag and drop, saved data | Kanban board | Intermediate |
| Game loops, canvas, timing | Snake | Intermediate |
| Pixels, queues, file export | Pixel art editor | Intermediate |
| Closures, promises, exit codes | Mini test framework | Advanced |
| Scoring and ranking | Command palette with fuzzy match | Advanced |
| Parsing and dependency order | Tiny spreadsheet | Advanced |
| Binary data and privacy | Photo metadata stripper | Advanced |
Which JavaScript projects suit a complete beginner?
These five fit in one HTML file and one script. No server, no install. Each one leans on a single idea, and each fails visibly: a wrong card, a wrong date, a broken pattern. That makes bugs easy to see and easy to explain.
01 Memory match game
A grid of face-down cards where you flip two at a time and clear the board by finding every pair.
- Stack
- HTML, CSS, plain JavaScript.
- Teaches
- A single state object, click handlers, setTimeout, shuffling an array.
- First version
- A 4 by 4 grid with eight pairs. A mismatch flips back after about 800 milliseconds. A message when all pairs are found.
- Stretch goal
- Move counter, best score, keyboard play, and a harder 6 by 6 board.
- Time
- 3 to 5 hours.
Two details separate a working game from a buggy one. First, ignore clicks while a mismatched pair is still showing, or fast clickers flip a third card. Second, shuffle with the Fisher-Yates method, not by sorting with a random comparison, which does not give every order the same chance. Keep the board in one object and redraw from it. Do not read the state back out of the page.
02 Live regex tester
A pattern box, a flags box and a sample text, with every match highlighted as you type.
- Stack
- HTML, CSS, plain JavaScript.
- Teaches
- RegExp, try and catch, escaping text before it goes into the page.
- First version
- Highlight all matches with String.prototype.matchAll. Show a red message when the pattern is invalid, instead of crashing.
- Stretch goal
- List capture groups per match, and warn when a pattern takes more than 100 milliseconds on your sample.
- Time
- 4 to 6 hours.
The part that teaches the most is safe output. Sample text can contain angle brackets, so build the highlighted result from text nodes and spans, or escape it first. Never paste it in as raw HTML. That one habit prevents most cross-site scripting bugs you will write later. An invalid pattern throws a SyntaxError when you construct the RegExp, so wrap that line and show the message beside the box.
04 To-do list with undo and redo
A list where every add, tick and delete can be undone and redone, with the keyboard shortcuts you expect.
- Stack
- HTML, CSS, plain JavaScript.
- Teaches
- Immutable updates, two stacks, event delegation, keyboard events.
- First version
- Add, tick and delete items. Undo and redo buttons that step through history.
- Stretch goal
- Ctrl or Cmd+Z and Shift+Z, history saved in the browser’s Web Storage, and a cap of 100 steps.
- Time
- 4 to 6 hours.
Keep the list as an array you never change in place. Each action produces a new array and pushes the old one onto an undo stack. Undo pops from that stack and pushes the current list onto a redo stack. Any new action empties the redo stack. This is the same idea that sits behind undo in editors and behind state history in many front-end libraries, which is why it is worth building once by hand.
05 Currency converter that works offline
Convert an amount between two currencies using rates fetched from a free API and remembered for the next visit.
- Stack
- HTML, CSS, plain JavaScript, the Fetch API.
- Teaches
- fetch, JSON, loading and error states, caching with a timestamp, Intl.NumberFormat.
- First version
- Fetch the latest rates, fill two drop-downs, convert on input. Show the rate’s date. Show an error line when the request fails.
- Stretch goal
- Use the cached rates when offline, and draw a 30-day line chart in SVG from the historical endpoint.
- Time
- 4 to 6 hours.
As of October 2026, Frankfurter describes itself as a free exchange rates API that needs no API key, which makes it a good first API: nothing secret has to go in your page. Store the rates with the time you fetched them and show that time. Format output with Intl.NumberFormat using the currency style rather than adding symbols by hand. Treat the result as an estimate for display. Floating-point maths is fine here and wrong for anything that moves money.
Build a single-page currency converter in plain HTML, CSS and JavaScript. No framework, no build step, no API key. Data: fetch the latest rates from the Frankfurter API and keep them in Web Storage with the time they were fetched. Screen: an amount field, two currency drop-downs, a swap button, the result formatted with Intl.NumberFormat, and a line saying when the rates are from. Do not build: charts, accounts, or any server code. Done when: converting 100 EUR to EUR gives 100.00, swapping twice returns the original pair, and turning off the network still shows the last saved rates with a note.
Which JavaScript projects come after the basics?
At this level the browser starts to push back. Requests arrive out of order, drag events fire in an order you did not expect, a game loop runs at different speeds on different screens. Each project below is picked because it forces you to meet one of those problems and fix it properly.
01 Search-as-you-type for Wikipedia
A search box that shows matching Wikipedia articles while you type, without showing stale results.
- Stack
- HTML, CSS, plain JavaScript, the MediaWiki API.
- Teaches
- Debouncing, AbortController, race conditions, CORS, keyboard navigation.
- First version
- Wait 250 milliseconds after the last keystroke, then request 8 results and list the titles with a one-line description.
- Stretch goal
- Arrow keys to move through results, bold the matched letters, and remember the last 20 queries in a Map.
- Time
- 5 to 8 hours.
The bug to find on purpose: type “java” and then “javascript” quickly on a slow connection. The answer for “java” can arrive last and overwrite the better one. Fix it by aborting the previous request every time you send a new one. The MediaWiki API documents how cross-origin requests work: for anonymous requests from a browser page you add an origin parameter to the query string. Read that page before you guess at the parameter.
02 Kanban board with drag and drop
Three columns of cards that you drag between, with the order saved in the browser.
- Stack
- HTML, CSS, plain JavaScript, the HTML Drag and Drop API.
- Teaches
- dragstart, dragover and drop events, dataTransfer, event delegation, saving and loading JSON.
- First version
- Add a card to any column, drag it to another column, and see the layout again after a reload.
- Stretch goal
- Drop between cards with a visible insertion line, move cards with the keyboard, and add a version number to the saved data.
- Time
- 8 to 12 hours.
Store cards as a flat list with an id, a column and a position, not as nested HTML you re-read. Drag events fire a lot, and the drop target is often a child of the thing you meant. Attach one listener to the board and find the column from the event target. Add a version number to the saved JSON from day one: the first time you change the shape, old saved boards will break without it.
03 Snake on canvas
The classic game, drawn on a canvas, with a snake that grows when it eats and ends when it hits a wall or itself.
- Stack
- HTML, plain JavaScript, the Canvas API.
- Teaches
- requestAnimationFrame, a fixed time step, grid maths, collision checks, input queues.
- First version
- A 20 by 20 grid, arrow keys, one apple at a time, a score, and a restart key.
- Stretch goal
- Speed up every five apples, store a high score, swipe controls on a phone, and a seeded random generator so you can replay a run.
- Time
- 6 to 10 hours.
Run the game logic on a fixed step, for example every 100 milliseconds, and draw on every frame from requestAnimationFrame. Otherwise the snake is faster on a 120 Hz screen. The classic bug is pressing two arrow keys inside one step, so a snake moving right turns up and then left and runs into itself. Queue the turns and apply one per step.
04 Pixel art editor
A 32 by 32 grid where you pick colors, paint, fill and export the result as a PNG.
- Stack
- HTML, CSS, plain JavaScript, canvas.
- Teaches
- Pointer events, pixel arrays, flood fill with a queue, canvas toBlob, file download.
- First version
- Click and drag to paint, a 16-color palette, an eraser, and a Download PNG button.
- Stretch goal
- Undo, a bucket fill, a shareable palette in the URL, and export of several frames as a sprite sheet.
- Time
- 10 to 15 hours.
Keep the picture as an array of color indexes and treat the canvas as only a view of it. Write bucket fill with a queue of pixels to visit. A fill written as a function that calls itself runs out of stack on a large empty area, which is a good way to learn why. Scale the saved PNG up so a 32-pixel image does not export as a speck, and turn off image smoothing when you draw it.
Which JavaScript projects teach how the tools work?
Advanced does not mean large. These four are small programs that copy the core of a tool you use every day: a test runner, a search palette, a spreadsheet, a privacy filter. You learn the most when you can compare your version with the real thing.
01 Mini test framework
A tiny library with describe, it and expect, run from the command line, that reports passes and failures and sets a failing exit code.
- Stack
- Node, plain JavaScript modules.
- Teaches
- Closures, promises, async tests, timeouts, try and catch, process exit codes.
- First version
- Register tests with it(name, fn), run them in order, print a tick or a cross, and exit with code 1 if any failed.
- Stretch goal
- beforeEach and afterEach, a filter by name, a readable diff for objects, and a watch mode.
- Time
- 8 to 12 hours.
The interesting step is making async tests work: await each function, and race it against a timer so a test that never resolves fails instead of hanging. Then use your framework to test your own code, which is the first time its error messages matter to you.
Write a minimal test framework in Node with plain ES modules. No dependencies. API: describe(name, fn), it(name, fn), expect(value).toBe(x), .toEqual(x), .toThrow(). Runner: a file test.js that imports the files given on the command line, runs every it() in order, awaits async functions, fails any test that takes over 2 seconds, prints a tick or cross with the test name, then a summary line. Exit code: 0 if all passed, 1 otherwise. Do not build: mocks, coverage, parallel runs. Done when: I can run `node test.js example.test.js` against a file with one passing, one failing and one slow test, and the output and exit code are correct.
02 Command palette with fuzzy match
Press Ctrl or Cmd+K, type a few letters, and pick from a ranked list of commands.
- Stack
- HTML, CSS, plain JavaScript, the dialog element.
- Teaches
- Scoring functions, sorting, focus management, keyboard handling, highlighting matches safely.
- First version
- 200 hard-coded commands, a subsequence match, results sorted by score, arrow keys and Enter.
- Stretch goal
- Recent commands first, a weight for how often you pick each one, and shortcuts shown beside each command.
- Time
- 8 to 12 hours.
Write the scoring function first and test it as a table of cases. A query matches when its letters appear in order. Give a bonus when letters are consecutive and when a letter starts a word. Worked example: for the query “gp”, “Go to Projects” should rank above “Upgrade plan”, because both letters start words in the first and only one does in the second. If your function disagrees, fix the function before building any screen.
03 Tiny spreadsheet
A grid where a cell can hold a number, text or a formula such as =A1+B2*2 or =SUM(A1:A5), and changes ripple through.
- Stack
- HTML, CSS, plain JavaScript.
- Teaches
- Tokenizing, a recursive-descent parser, dependency graphs, cycle detection, memoizing.
- First version
- A 10 by 10 grid, formulas with plus, minus, times, divide and brackets, and cell references.
- Stretch goal
- SUM and AVERAGE over ranges, a #CYCLE marker when A1 depends on A1, and saving to a CSV file.
- Time
- 15 to 25 hours.
Do not use eval. Write a small parser that turns a formula into a tree and evaluates the tree. When a cell changes, find every cell that depends on it and recompute them in dependency order. A cycle is not a crash, it is a state your sheet has to show. Test with three hand-worked sheets before touching the interface.
04 Photo metadata stripper
Drop in a JPEG and get the same picture back without its location and camera data, with nothing uploaded anywhere.
- Teaches
- Binary formats, ArrayBuffer, big-endian numbers, Blob downloads, privacy by design.
- First version
- Read the file into an ArrayBuffer, walk the JPEG segments, drop the ones that carry EXIF, and offer the rebuilt file for download.
- Stretch goal
- Show what was found (camera, date, GPS position) before removing it, then handle PNG and WebP too.
- Time
- 10 to 15 hours.
A JPEG is a list of segments. Each starts with the byte 0xFF and a marker. After the first two bytes of the file, each marker is followed by a two-byte length that includes itself. EXIF lives in an APP1 segment, marker 0xFFE1. Copy every segment except those. When you reach the start-of-scan marker, 0xFFDA, copy the rest of the file unchanged, because that is the image data. Redrawing the picture on a canvas also drops metadata, but it re-compresses the image and loses quality. Editing the bytes does not.
Build a single-page tool in plain HTML and JavaScript that removes EXIF data from a JPEG entirely in the browser. No upload, no server, no libraries. Flow: the user drops a .jpg file. Read it with the File API into an ArrayBuffer. Check it starts with bytes FF D8. Walk the segments, skipping any APP1 segment whose payload starts with "Exif". Copy everything else, including the image data, into a new Blob and show a Download button. Show before and after file sizes. Do not build: PNG support, canvas re-encoding, cropping. Done when: a test photo with GPS data opens in an EXIF viewer with no location after processing, and the picture looks identical.
Where can I find JavaScript project ideas that real people want?
A project gets easier to finish when someone other than you wants it. The board at Post your build ideas holds ideas that people posted because they will never build them. Browse all ideas, or the developer tools and productivity categories, and look for one that is a single screen with no login. Every idea has a generated build prompt you can paste into Claude Code, Cursor or Lovable.
A few posted on the board are close in size to the beginner projects above: Explain this cron expression in plain English is a parser and a lookup table, and Clak, a typing test is about key events and timing. Posted does not mean validated, so ask a real person whether they would use the result before you spend a weekend. If you have an idea you will not build, post it: it needs no account.
If you build with an AI tool, the same rules apply: write the check first, read what comes back, and keep the first prompt to one screen. How to write an app build prompt explains the format used in the prompts above.
Frequently asked questions
What JavaScript projects should a beginner start with?
Start with a single-page project that uses one idea: a memory match game for state, a regex tester for errors, or a countdown for dates. Each fits in one HTML file, runs without installing anything, and fails in a way you can see. Finish two before you try a project with an outside API.
How many JavaScript projects do I need to learn the language?
There is no fixed number. A useful target is one project per core idea: state, events, dates, async requests, saved data and a game loop. That is about six small projects. Finishing, deploying and explaining four of them teaches more than starting twenty.
Should I build JavaScript projects without a framework?
Build at least two without one. Plain JavaScript shows you the DOM, events and state directly, so a framework later has something to replace in your head. Then move to React or another tool for projects with many moving parts, such as a data table or a form with several steps.
Can I use an AI coding tool for these projects?
Yes, and the first prompts here are written for that. The skill to practice is checking the result. Write one worked example before you start, run it yourself, and read the code for the one concept the project is meant to teach. If you cannot explain that part, ask the tool to explain it.
Where do I host a JavaScript project for others to see?
Any static host serves a plain HTML and JavaScript project, since there is nothing to run on a server. GitHub Pages, Netlify, Cloudflare Pages and Vercel all do this. Put the project in a repository with a README that has a screenshot and one line about what it teaches.
How do I make a JavaScript project look good in a portfolio?
Pick a project that solves a small real problem, write a short README with a screenshot, and list what you chose not to build. Reviewers read decisions more than features. A tested, deployed, small project beats a large one that only runs on your laptop.
Created with AI assistance and edited for this site. Examples are illustrative and do not represent customer research. About the publisher.