A to-do app built on localStorage is one of the best small frontend projects for a two-week internship, because it forces you to handle data, events, rendering and persistence in a single codebase. Build it in vanilla JavaScript with add, edit, delete, complete, filter and reload-safe saving, test it against a bug checklist, and you will have a portfolio piece you can explain line by line.
Why a browser-storage task app suits a 14-day internship
The project is small enough to finish and deep enough to discuss in an interview. You touch the DOM, event handling, array methods, JSON, and the browser’s Web Storage API without needing a server or a framework. That matters when you have 14 days and probably other classes running alongside.
The free two-week online internship at CareerSwami is structured around the same idea: a short, bounded build that ends with something you can show. CareerSwami offers a free offer letter and a free completion certificate after successful completion, across 26 tracks. Nothing here promises a stipend, academic credit or a job; the value is the project and what you learn.
What you will have at the end
- A working task app that survives page reloads and browser restarts.
- Inline editing, completion toggling, deletion and three filters (all, active, completed).
- A tested list of edge cases you can describe in a README.
- A public repository and a deployed page you can link from a resume.
How localStorage actually works, in the parts that matter
localStorage stores key-value pairs in the browser for a specific origin (protocol, domain and port). Values are always strings, so you convert your task array with JSON.stringify on save and JSON.parse on load. Data stays until the user clears site data or your code removes it. It is not private, not encrypted and not synced between devices, so never store passwords or anything sensitive.
- Origin-bound: opening
file://andhttp://localhost:5500give separate storage, which confuses many beginners. - Synchronous: fine for a few hundred tasks, not for large data.
- Size-limited: typically a few megabytes per origin, which varies by browser.
- Can fail: private browsing modes or full storage can throw errors, so wrap access in
try/catch.
Free 2-Week CareerSwami Internship
Online, 14 days, with a free offer letter and a free completion certificate once you finish the work. Check with your college that it fits your requirement before you enrol.
Data model: decide the task shape before writing any UI
Most bugs in beginner to-do apps come from a weak data model. Use an array of objects, each with a stable unique id, rather than relying on array position.
// Illustrative task shape
{
id: "t_1731480000000",
text: "Revise array methods",
done: false,
createdAt: 1731480000000
}
Keep one source of truth: a single tasks array in memory. Every user action updates that array, saves it, then re-renders the list from it. Never read state back from the DOM.
A day-by-day 14-day build plan for the to-do app
| Day | Focus | Output |
|---|---|---|
| 1 | Setup and semantic HTML | Repo created, form, list container, filter buttons |
| 2 | Base CSS and layout | Responsive card layout, readable at 360px width |
| 3 | State array and render function | Tasks drawn from an in-memory array |
| 4 | Add task with validation | Empty and whitespace-only input rejected |
| 5 | Complete and delete | Checkbox toggle, delete button using event delegation |
| 6 | Save to localStorage | save() called after every change |
| 7 | Load on startup, handle bad data | load() with try/catch and fallback to empty array |
| 8 | Inline edit | Double-click or edit button, Enter saves, Escape cancels |
| 9 | Filters | All, active, completed views; remaining-count label |
| 10 | Persist the active filter | Filter choice survives reload (separate key) |
| 11 | Accessibility pass | Labels, focus states, keyboard-only use |
| 12 | Bug checklist testing | Every row below tested and logged |
| 13 | Deploy and README | Live page, screenshots, feature list |
| 14 | Extension and review | One extension added, repo cleaned up |
Core code patterns for saving, loading and rendering
The three functions below are the backbone. They are illustrative sketches to adapt, not tested production code.
const KEY = "tasks.v1";
let tasks = load();
function load() {
try {
const raw = localStorage.getItem(KEY);
const parsed = raw ? JSON.parse(raw) : [];
return Array.isArray(parsed) ? parsed : [];
} catch (e) {
return [];
}
}
function save() {
try {
localStorage.setItem(KEY, JSON.stringify(tasks));
} catch (e) {
showMessage("Could not save. Storage may be full or blocked.");
}
}
function render() {
list.innerHTML = "";
visibleTasks().forEach(t => list.appendChild(taskNode(t)));
}
Note the .v1 suffix in the key. If you later change the task shape, you can migrate old data instead of crashing on it.
Why you should avoid building the list with innerHTML and user text
If you insert task text into innerHTML, a task like <img src=x onerror=alert(1)> will run as code. Create elements with document.createElement and set textContent. This is a real security habit that interviewers notice.
Worked illustrative example: tracing one edit through the whole app
This walk-through is illustrative and shows the logic, not a recorded test run. Suppose the stored value is one task, “Read MDN fetch docs”, with id t_1.
- The user double-clicks the text. The app swaps the label for an input pre-filled with the current text and focuses it.
- The user changes it to “Read MDN fetch and Promise docs” and presses Enter.
- The handler trims the value. If it is empty, the app either cancels the edit or asks to delete; pick one rule and apply it consistently.
- The app finds the task by id (not by index), updates
text, callssave(), then callsrender(). - On reload,
load()parses the saved JSON and the edited text appears.
If the user pressed Escape in step 2, no state change happens and the original text returns. Testing both paths is part of the checklist below.
Feature checklist for the localStorage task app
| Feature | Done when | Status |
|---|---|---|
| Add task | Enter key and button both work; input clears and refocuses | Not started |
| Validation | Blank and spaces-only input rejected with a visible message | Not started |
| Complete toggle | Checkbox changes state, styling changes, saved | Not started |
| Delete | Removes the correct task even with duplicate text | Not started |
| Inline edit | Enter saves, Escape cancels, blur behaviour defined | Not started |
| Filters | All, active, completed show the right items | Not started |
| Counter | Shows remaining active tasks correctly, including singular and plural | Not started |
| Persistence | Tasks and filter survive reload and browser restart | Not started |
| Clear completed | Removes only done tasks | Not started |
| Empty state | Friendly message when no tasks match the filter | Not started |
| Keyboard use | Every action reachable without a mouse | Not started |
| Responsive layout | Usable on a phone-width screen | Not started |
Bug checklist: failures a localStorage to-do app commonly hits
| Symptom | Likely cause | Fix |
|---|---|---|
| Tasks vanish on reload | save() not called after one of the actions, or wrong key on load | Use one KEY constant; call save() inside a single update helper |
| Page shows “[object Object]” | Object saved without JSON.stringify | Stringify on save, parse on load |
| App crashes on startup | Corrupted or old-format data in storage | try/catch in load(), validate it is an array |
| Wrong task deleted or edited | Using array index after filtering | Always look up by id |
| Duplicate click handlers | Listeners attached inside render() | Use one delegated listener on the list |
| Edit saves empty text | No trim or empty check on edit path | Share validation with the add path |
| Data differs between localhost and file | Different origins | Always run from the same local server address |
| Filter resets on reload | Filter kept only in a variable | Store it under a second key |
| Task text runs as HTML | innerHTML with user input | createElement and textContent |
| Two tabs overwrite each other | Each tab holds a stale array | Listen for the storage event and reload state |
Manual test script to run on Day 12
- Open DevTools, then Application, then Local Storage, and watch the key change as you act.
- Add five tasks, including two with identical text. Delete one of the duplicates and confirm the right one goes.
- Complete two tasks, switch to each filter, then reload. Confirm filter and tasks persist.
- Edit a task, press Escape, and confirm nothing changed. Edit again and press Enter.
- Manually set the stored value to
{bad jsonand reload. The app should start empty, not crash. - Paste an HTML tag as a task and confirm it displays as plain text.
- Open the app in two tabs, change a task in one, and see what the other does.
- Use only the keyboard from start to finish.
K.K. University students: fitting this frontend build into your own academic setup
K.K. University’s About page describes it as a state private university in Nalanda district, Bihar, established under the Bihar Private Universities Act, 2013. The same page says the university follows NEP 2020 and collaborates with industry on skill development and internships. It does not give a duration, credit value, evaluation method or any mention of online internships, so you should not assume an online internship like this one counts toward anything in your degree.
That distinction matters in practice. Treat this build as skill-building and portfolio work first. If you want it recognised in your department, whether as a project, a training log or supporting evidence, that is a decision for your department and not something this guide can promise.
The university’s Training & Placement page names placement@kkuniversity.ac.in as the cell’s contact and says the cell covers Engineering, Pharmacy, Agriculture, Law, Management & Commerce, Applied Sciences and Teacher Training. That is a sensible place to ask how portfolio projects and certificates are viewed. The site also links a Programme Structure & Syllabus page and an Academic Calendar page; check the current versions of both for your course and semester before planning your 14 days around exams.
Verification steps for KKU students before you rely on this internship
- Open the Programme Structure & Syllabus page for your course and look for any internship, training or project component, noting the semester and scheme year.
- Read the Academic Calendar and Examination Calendar to pick 14 days that avoid exams and submissions.
- Email your department coordinator asking in writing whether an online internship certificate can be submitted as supporting evidence, and what format is needed.
- Ask the same question to the Training & Placement cell at placement@kkuniversity.ac.in, and keep the reply.
- Look in The First Ordinance, linked from the university site menu, for any rules on internships or project work, and ask your department to point out the relevant clause if there is one.
Extension ideas that turn the task app into a stronger portfolio piece
Add only one or two extensions. A polished small app beats a messy large one.
- Due dates and overdue styling: practise the Date object and sorting.
- Priority and tags: extend the data model and add multi-condition filtering.
- Search box: filter by text as you type, with debouncing.
- Drag-and-drop reordering: use the HTML Drag and Drop API and persist the order.
- Undo after delete: a brief toast with an undo button teaches state history.
- Export and import JSON: a download button and file input give users a backup.
- Dark mode: use CSS variables and store the preference.
- Migration logic: bump the key to
tasks.v2and convert old data, which is a strong interview story. - Refactor to modules: split storage, state and UI into separate files with ES modules.
- Automated tests: write unit tests for the pure functions once you are comfortable with a test runner.
Presenting the finished to-do app on GitHub and in your resume
Your README is part of the project. Include a screenshot or short GIF, a feature list, how to run it, and a short “what I learned” paragraph. Add a “known limitations” line, for example that data is stored only in one browser and is not synced.
On a resume, write one factual line such as: “Built a task manager in vanilla JavaScript with inline editing, filtering and localStorage persistence; handled corrupted storage data and escaped user input.” Only claim what you can demonstrate if asked.
Frequently Asked Questions
Do I need React or another framework for this project as a K.K. University student?
No. Vanilla JavaScript is better for learning because you see exactly how state, rendering and events fit together. You can rebuild the same app in a framework afterwards and compare.
Is localStorage safe for storing tasks?
It is fine for non-sensitive data like task text. Any script on the same origin can read it, and users can edit it in DevTools, so never store passwords, tokens or personal records there.
Why do my tasks disappear when I open the file a different way?
Storage is tied to the origin. Opening the page via file://, one local server port, or a deployed URL creates separate storage areas. Pick one way of running the app while you test.
What is the difference between localStorage and sessionStorage?
localStorage persists until cleared. sessionStorage lasts only for that tab’s session and is wiped when the tab closes. A to-do app that must survive restarts needs localStorage.
Can I use this project for my college internship requirement at K.K. University?
That depends on your department’s rules, which the university’s public About page does not spell out for online internships. Ask your coordinator in writing and keep the reply, using the verification steps above.
How many tasks can localStorage hold?
The limit varies by browser and is usually a few megabytes per origin. A task list will rarely approach it, but your save function should still handle a failure gracefully.
Should I store the filter choice in localStorage too?
It is a good small feature. Use a separate key, such as filter.v1, and validate the loaded value against your allowed options (all, active, completed) before using it.
What should I add first if I only have time for one extension?
Export and import JSON, or due dates. Both extend the data model, touch persistence, and give you a clear point to discuss in an interview.
Related Frontend Development guides
- Malla Reddy University Students: Frontend Internship Resume Project Selection, Two Strong Beats Five Weak
- Bareilly International University: Frontend Internship Accessibility on a Budget for Small Business Sites
- O.P. Jindal University Students: Frontend Internship Guide to Handling Feedback and Revisions
- All Frontend Development internship guides
Ready to put this into practice?
Join the free two-week CareerSwami online internship in Frontend Development. The internship, the offer letter and the completion certificate are free.














