Build Three Real-World Projects
Employers don't care about what you know — they care about what you've built. These three projects cover every skill you've learned and are designed to be the core of your developer portfolio.
ℹ️ How to approach these projects
Each project below gives you the architecture blueprint and core logic. Your job is to implement the full design using the HTML, CSS, and JS skills from Modules 1–3. Don't copy-paste — type every line yourself.
1
Portfolio Website
Objective: Build a personal brand site that showcases who you are and what you've built. This is the first thing every employer will ask to see.
Skills Practiced
HTML
Semantic structure
Header, nav, sections for hero, projects, and contact.
CSS
Grid + Flexbox layout
Responsive project cards, sticky navigation, dark mode.
JavaScript
Theme toggle
Scroll animations and smooth anchor navigation.
Deployment
GitHub Pages
Push to a public repo and enable Pages in Settings.
Key Implementation: Dark Mode Toggle
javascript
const toggleBtn = document.querySelector('#themeToggle');
const root = document.documentElement;
// On load: restore saved preference
const saved = localStorage.getItem('theme') || 'dark';
root.setAttribute('data-theme', saved);
toggleBtn.addEventListener('click', () => {
const current = root.getAttribute('data-theme');
const next = current === 'dark' ? 'light' : 'dark';
root.setAttribute('data-theme', next);
localStorage.setItem('theme', next);
});
Key Implementation: Scroll-Triggered Animation
javascript — IntersectionObserver
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('visible');
}
});
}, { threshold: 0.1 });
document.querySelectorAll('.project-card').forEach(card => {
observer.observe(card);
});
css — Fade-in animation
.project-card {
opacity: 0;
transform: translateY(24px);
transition: opacity 0.5s ease, transform 0.5s ease;
}
.project-card.visible {
opacity: 1;
transform: translateY(0);
}
2
TaskFlow — Task Manager App
Objective: Build a fully-functional task management app using only vanilla JavaScript. No libraries. This project tests your ability to manage application state.
Skills Practiced
Core Concept
State Management
Keep your data (tasks array) as the single source of truth and always re-render from it.
Core Concept
Data Persistence
Save tasks to
localStorage so they survive a page refresh.CRUD Operations
Create, Read, Update, Delete
The core operations of every real-world application.
UX Feature
Filtering
Filter tasks by "All", "Active", and "Completed" status.
The Core Architecture
javascript — State-Driven UI Pattern
// 1. STATE — the single source of truth
let tasks = JSON.parse(localStorage.getItem('tasks')) || [];
// 2. RENDER — always re-draw from state (never mutate the DOM directly)
const renderTasks = (filter = 'all') => {
const list = document.querySelector('#taskList');
const filtered = tasks.filter(t => {
if (filter === 'active') return !t.completed;
if (filter === 'completed') return t.completed;
return true; // 'all'
});
list.innerHTML = filtered.map((task, i) => `
<li class="task ${task.completed ? 'done' : ''}">
<input type="checkbox"
${task.completed ? 'checked' : ''}
onchange="toggleTask(${i})">
<span>${task.text}</span>
<button onclick="deleteTask(${i})">✕</button>
</li>
`).join('');
};
// 3. ACTIONS — modify state, then re-render
const addTask = (text) => {
tasks.push({ text, completed: false, id: Date.now() });
save();
renderTasks();
};
const toggleTask = (index) => {
tasks[index].completed = !tasks[index].completed;
save();
renderTasks();
};
const deleteTask = (index) => {
tasks.splice(index, 1);
save();
renderTasks();
};
// 4. PERSIST — sync state to localStorage
const save = () => localStorage.setItem('tasks', JSON.stringify(tasks));
// 5. INIT — render on page load
renderTasks();
3
WeatherPulse — API Dashboard
Objective: Build a real-time weather dashboard that fetches live data from the OpenWeatherMap API. This project proves you can work with external services.
Setup — Getting Your Free API Key
- Go to openweathermap.org and create a free account.
- Navigate to My API Keys and copy your key.
- Store it in your JS file as a constant (never commit real keys to public GitHub repos).
The Core Fetch Logic
javascript — Full Fetch with Loading States
const API_KEY = 'YOUR_API_KEY_HERE';
const BASE_URL = 'https://api.openweathermap.org/data/2.5/weather';
const getWeather = async (city) => {
const spinner = document.querySelector('.spinner');
const errorEl = document.querySelector('.error-msg');
// Show loading state
spinner.classList.remove('hidden');
errorEl.classList.add('hidden');
try {
const url = `${BASE_URL}?q=${city}&appid=${API_KEY}&units=metric`;
const res = await fetch(url);
if (!res.ok) throw new Error('City not found');
const data = await res.json();
renderWeather(data);
} catch (err) {
errorEl.textContent = err.message;
errorEl.classList.remove('hidden');
} finally {
spinner.classList.add('hidden');
}
};
const renderWeather = (data) => {
document.querySelector('#city-name').textContent = data.name;
document.querySelector('#temp').textContent = `${Math.round(data.main.temp)}°C`;
document.querySelector('#condition').textContent = data.weather[0].description;
document.querySelector('#humidity').textContent = `${data.main.humidity}%`;
document.querySelector('#wind').textContent = `${data.wind.speed} m/s`;
};
// Trigger on search form submit
document.querySelector('#searchForm').addEventListener('submit', (e) => {
e.preventDefault();
const city = document.querySelector('#cityInput').value.trim();
if (city) getWeather(city);
});
💡 Portfolio Tip
Add geolocation using
navigator.geolocation.getCurrentPosition() to detect the user's city automatically on page load. This single feature makes the project feel like a professional app.