DOCODIVE
Intermediate Free Learning Path

Web Development Intermediate Course

Level up from basics to real apps. Master CSS Grid, Flexbox, animations, modern JavaScript, fetch APIs, async/await, localStorage, and build a complete interactive dashboard.

5–7 weeks 20 lessons 3 projects 1 capstone Beginner knowledge required
Start Learning
01

CSS Grid Mastery

18 min
What you'll learn
  • Build 2D layouts
  • Use grid-template-columns
  • Place items with grid areas

CSS Grid is the most powerful layout tool in modern web development. Unlike Flexbox (one dimension), Grid controls both rows and columns at once. You define columns with grid-template-columns, rows with grid-template-rows, and place items anywhere. This is how professional dashboards, photo galleries, and app layouts are built today.

grid.css
.gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 12px;
}
.gallery-item {
  background: #6366f1;
  color: white;
  padding: 24px;
  text-align: center;
  border-radius: 12px;
  font-weight: 700;
}
Live Preview
browser — CSS Grid Mastery
1
2
3
4
5
6
✓ Best Practice: Use Grid for page-level layout (rows AND columns), Flexbox for one-dimensional alignment inside components.
Try it yourself

Create a 4-column grid with 16px gaps.

grid-template-columns: repeat(4, 1fr); gap: 16px;
.grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 16px;
}
02

Flexbox Deep Dive

16 min
What you'll learn
  • Master justify-content and align-items
  • Use flex-grow and flex-shrink
  • Build navbar layouts

Flexbox excels at one-dimensional layout — a row or a column. The real power is in distribution: justify-content controls spacing along the main axis, align-items across it, and flex-grow lets items expand to fill remaining space. Nearly every navbar, button group, and card row uses these properties.

flex.css
.navbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 12px 20px;
}
.nav-links {
  display: flex;
  gap: 16px;
}
.logo {
  font-weight: 800;
  color: #4f46e5;
}
Live Preview
browser — Flexbox Deep Dive
💡 Tip: gap works in modern Flexbox — no more margin hacks between items.
Try it yourself

Use flexbox to center a single box both horizontally and vertically.

display:flex; justify-content:center; align-items:center;
.center {
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
}
03

CSS Transitions & Animations

18 min
What you'll learn
  • Animate smooth state changes
  • Create keyframe animations
  • Understand easing curves

Transitions smoothly change a property when state changes (like hover). Keyframe animations run continuously or on load without needing a state change. Together they make interfaces feel alive — buttons that lift, cards that fade in, spinners that rotate forever.

animation.css
.btn {
  padding: 12px 24px;
  background: #6366f1;
  color: white;
  border: none;
  border-radius: 8px;
  transition: transform 0.2s ease, background 0.2s ease;
}
.btn:hover {
  transform: translateY(-3px);
  background: #4f46e5;
}
@keyframes spin {
  to { transform: rotate(360deg); }
}
.spinner {
  width: 40px;
  height: 40px;
  border: 4px solid #e0e7ff;
  border-top-color: #6366f1;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}
Live Preview
browser — CSS Transitions & Animations

Spinning forever

🔎 Important: For performance, animate only transform and opacity — never width/height.
Try it yourself

Add a hover effect that scales an element to 1.05 over 0.3 seconds.

transition: transform 0.3s; :hover { transform: scale(1.05); }
.card { transition: transform 0.3s ease; }
.card:hover { transform: scale(1.05); }
04

CSS Gradients & Shadows

14 min
What you'll learn
  • Create linear/radial gradients
  • Layer box-shadows
  • Design modern cards

Gradients add depth and color richness without images — linear-gradient goes in a straight line, radial-gradient from a center point. Box-shadow layers create realistic elevation. Combined, they make the modern 'soft UI' card look that's everywhere today.

gradient.css
.hero-card {
  background: linear-gradient(135deg, #6366f1, #8b5cf6);
  padding: 32px;
  border-radius: 20px;
  color: white;
  box-shadow: 0 20px 40px rgba(99, 102, 241, 0.35);
}
Live Preview
browser — CSS Gradients & Shadows
Gradient Card

linear-gradient(135deg, #6366f1, #8b5cf6)

✓ Best Practice: Use a low-opacity shadow color matching your brand for a professional glow effect.
Try it yourself

Create a radial gradient from light to dark blue.

background: radial-gradient(circle, #dbeafe, #1e3a8a);
.bg { background: radial-gradient(circle, #dbeafe, #1e3a8a); }
05

CSS Variables (Custom Properties)

14 min
What you'll learn
  • Define reusable values
  • Build themeable designs
  • Override variables locally

CSS variables (--name) store values once and reuse them everywhere. Change one variable and the whole site updates — perfect for themes, brand colors, and spacing systems. They're the foundation of design systems like Tailwind's config.

variables.css
:root {
  --primary: #6366f1;
  --radius: 12px;
  --spacing: 16px;
}
.btn {
  background: var(--primary);
  border-radius: var(--radius);
  padding: var(--spacing);
  color: white;
  border: none;
}
Live Preview
browser — CSS Variables (Custom Properties)
Styled by variables
✓ Best Practice: Always define variables in :root so they're globally available to every element.
Try it yourself

Define a --accent variable and use it to color a heading.

:root { --accent: orange; } h1 { color: var(--accent); }
:root { --accent: #f59e0b; }
h1 { color: var(--accent); }
06

Mobile-First Responsive Patterns

16 min
What you'll learn
  • Design mobile-first
  • Use min-width breakpoints
  • Build adaptive grids

Mobile-first means you write base styles for small screens, then use min-width media queries to enhance for larger ones. It's easier than squeezing desktop layouts down, and it keeps your CSS lean. This is how production teams actually build responsive sites.

responsive.css
.grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
}
@media (min-width: 640px) {
  .grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 1024px) {
  .grid { grid-template-columns: repeat(4, 1fr); }
}
Live Preview
browser — Mobile-First Responsive Patterns
1
2
3
4
🔎 Important: Test in DevTools device mode — that's where responsive bugs hide.
Try it yourself

Add a min-width breakpoint at 768px that switches a 1-column layout to 3 columns.

@media (min-width: 768px) { grid-template-columns: repeat(3, 1fr); }
@media (min-width: 768px) {
  .grid { grid-template-columns: repeat(3, 1fr); }
}
07

JavaScript Arrays & Iteration

16 min
What you'll learn
  • Use map, filter, reduce
  • Iterate with forEach
  • Transform data arrays

Arrays hold lists of data, and the modern iteration methods are your daily tools. map() transforms each element into a new array, filter() keeps only matching items, reduce() boils an array down to one value. These three replace most loops you'd otherwise write by hand.

arrays.js
const numbers = [1, 2, 3, 4, 5];

const doubled = numbers.map(n => n * 2);
const evens = numbers.filter(n => n % 2 === 0);
const sum = numbers.reduce((total, n) => total + n, 0);

console.log(doubled, evens, sum);
Output
console
[2, 4, 6, 8, 10] [2, 4] 15
💡 Tip: Chain them: numbers.filter(...).map(...) is a clean data pipeline.
Try it yourself

Use map to convert ['a','b','c'] to ['A','B','C'].

.map(letter => letter.toUpperCase())
['a','b','c'].map(l => l.toUpperCase()); // ['A','B','C']
08

JavaScript Objects

15 min
What you'll learn
  • Create and access objects
  • Use dot vs bracket notation
  • Nest objects and arrays

Objects group related data under one name — a user has a name, email, and age. Access properties with dot notation (user.name) or bracket notation (user['name']) when keys are dynamic. Objects are the backbone of almost every API response you'll ever work with.

objects.js
const user = {
  name: 'Sufyan',
  age: 21,
  skills: ['HTML', 'CSS', 'JS'],
  address: {
    city: 'Lahore',
    country: 'Pakistan'
  }
};

console.log(user.name, user.address.city, user.skills[1]);
Output
console
Sufyan Lahore CSS
🔎 Important: Nested objects are everywhere in real APIs — get comfortable reading user.address.city style paths.
Try it yourself

Add a 'phone' property to user and log it.

user.phone = '0300-123';
user.phone = '0300-123';
console.log(user.phone);
09

Advanced DOM Manipulation

18 min
What you'll learn
  • Create and remove elements
  • Toggle CSS classes
  • Build dynamic lists

Beyond changing text, real apps create and destroy elements at runtime. createElement builds new nodes, appendChild adds them, classList.toggle switches styling, and remove() deletes them. Master these four and you can build any dynamic interface.

dom.js
const list = document.querySelector('#list');
const btn = document.querySelector('#add');

btn.addEventListener('click', () => {
  const item = document.createElement('li');
  item.textContent = 'New item';
  item.classList.add('active');
  list.appendChild(item);
});
Live Preview
browser — Advanced DOM Manipulation
Learn JS
Build app
Deploy site
✓ Best Practice: Use classList.toggle('active') for show/hide and theme switches — cleaner than inline styles.
Try it yourself

Write code that removes the last item from a list.

list.lastElementChild?.remove();
const last = list.lastElementChild;
if (last) last.remove();
10

Event Delegation

16 min
What you'll learn
  • Handle events efficiently
  • Use event.target
  • Avoid attaching many listeners

Instead of adding a listener to every list item (slow and buggy with new items), you add ONE listener to the parent and check event.target to see which child was clicked. This is event delegation — it automatically works for elements you add later.

delegation.js
const list = document.querySelector('#list');

list.addEventListener('click', (event) => {
  if (event.target.tagName === 'LI') {
    event.target.classList.toggle('done');
  }
});
Live Preview
browser — Event Delegation
Learn JS
Build app
Deploy site
🔎 Important: This is THE pattern for lists, tables, and grids where items change dynamically.
Try it yourself

Use delegation to console.log the text of a clicked button inside a container.

Listen on the container, check if target.tagName === 'BUTTON'.
container.addEventListener('click', e => {
  if (e.target.tagName === 'BUTTON') console.log(e.target.textContent);
});
11

LocalStorage Persistence

15 min
What you'll learn
  • Save data in the browser
  • Read and write JSON
  • Build persistent apps

localStorage lets your app remember data between page loads without a backend — perfect for themes, settings, and to-do lists. Everything is stored as strings, so use JSON.stringify to save and JSON.parse to load objects.

storage.js
// Save
const tasks = ['learn JS', 'build app'];
localStorage.setItem('tasks', JSON.stringify(tasks));

// Load
const saved = JSON.parse(localStorage.getItem('tasks'));
console.log(saved);
Output
console
['learn JS', 'build app']
⚠️ Common Mistake: localStorage is synchronous and limited (~5MB) — don't store large files or sensitive data there.
Try it yourself

Save a user object with a name and load it back.

JSON.stringify for setItem, JSON.parse for getItem.
localStorage.setItem('user', JSON.stringify({name:'Sufyan'}));
JSON.parse(localStorage.getItem('user'));
12

Fetch API — Making Requests

18 min
What you'll learn
  • Fetch data from APIs
  • Handle JSON responses
  • Understand async operations

fetch() is how your page talks to servers — getting weather, posts, users, anything. It returns a Promise because the request takes time. You chain .then() to parse the JSON response, and .catch() to handle failures. This is the gateway to real apps.

fetch.js
fetch('https://jsonplaceholder.typicode.com/posts/1')
  .then(response => response.json())
  .then(data => console.log(data.title))
  .catch(error => console.error('Failed:', error));
Output
console
sunt aut facere repellat provident occaecati excepturi optio reprehenderit
🔎 Important: Always check response.ok or use .catch() — network requests fail all the time.
Try it yourself

Fetch a user and log only their email.

fetch('/api/user').then(r=>r.json()).then(u=>console.log(u.email))
fetch('/api/user')
  .then(r => r.json())
  .then(u => console.log(u.email));
13

Async / Await

18 min
What you'll learn
  • Write cleaner async code
  • Replace promise chains
  • Handle multiple awaits

async/await makes asynchronous code read like synchronous code. Mark a function async, then await promises inside it. The code pauses at await until the result arrives — much easier to read and debug than nested .then() chains.

async.js
async function getUser() {
  const response = await fetch('https://jsonplaceholder.typicode.com/users/1');
  const user = await response.json();
  console.log(user.name);
}

getUser();
Output
console
Leanne Graham
✓ Best Practice: Prefer async/await over .then() chains — future-you debugging at 2am will be grateful.
Try it yourself

Write an async function that fetches posts and logs the count.

await fetch, await json, console.log(data.length).
async function countPosts() {
  const res = await fetch('/posts');
  const posts = await res.json();
  console.log(posts.length);
}
14

Error Handling in JavaScript

14 min
What you'll learn
  • Use try/catch
  • Handle async errors
  • Show friendly messages

Errors WILL happen — bad network, bad input, bad data. try/catch catches exceptions so your app doesn't crash silently. With async/await, wrap awaits in try/catch and show users a friendly fallback instead of a blank screen.

errors.js
async function loadData() {
  try {
    const res = await fetch('/api/data');
    if (!res.ok) throw new Error('Bad response');
    const data = await res.json();
    console.log(data);
  } catch (error) {
    console.error('Something went wrong:', error.message);
  }
}
Output
console
On failure: 'Something went wrong: Bad response' — no crash, just a logged error.
⚠️ Common Mistake: Never leave a catch block empty — silent failures are the hardest bugs to find.
Try it yourself

Wrap a fetch call in try/catch and log the error.

try { await fetch(...) } catch(e) { console.error(e); }
try {
  await fetch('/api');
} catch (e) {
  console.error(e.message);
}
15

ES6+ Essentials: Destructuring & Spread

16 min
What you'll learn
  • Destructure objects and arrays
  • Use spread/rest operators
  • Write cleaner modern JS

Destructuring pulls values out of objects and arrays in one line. The spread operator (...) copies arrays/objects, and rest collects the remainder. These modern features cut out so much boilerplate that they're now considered the default way to write JavaScript.

es6.js
const user = { name: 'Sufyan', age: 21, city: 'Lahore' };
const { name, age } = user;

const nums = [1, 2, 3];
const more = [...nums, 4, 5];

console.log(name, age, more);
Output
console
Sufyan 21 [1, 2, 3, 4, 5]
💡 Tip: Spread is the cleanest way to copy or merge arrays — no more .concat() everywhere.
Try it yourself

Destructure {a:1, b:2} to get a and b, then spread [1,2] with a 3.

const {a,b} = obj; [...arr, 3]
const {a, b} = {a:1, b:2};
const nums = [...[1,2], 3]; // [1,2,3]
16

Form Validation

18 min
What you'll learn
  • Validate user input
  • Show error messages
  • Use HTML5 + JS validation

Forms are where users interact most, and validation keeps data clean. HTML5 gives you required, minlength, and type=email for free. JavaScript adds custom rules and live error messages. Good validation prevents bad data before it ever reaches your server.

validation.js
const form = document.querySelector('form');
const email = document.querySelector('#email');
const error = document.querySelector('#error');

form.addEventListener('submit', (e) => {
  e.preventDefault();
  if (!email.value.includes('@')) {
    error.textContent = 'Please enter a valid email';
    error.style.display = 'block';
  } else {
    error.style.display = 'none';
    form.submit();
  }
});
Live Preview
browser — Form Validation
⚠ Please enter a valid email
🔎 Important: Always validate on the server too — client-side validation is for UX, not security.
Try it yourself

Add a check that requires at least 3 characters in a name field.

if (name.value.length < 3) show error.
if (name.value.trim().length < 3) {
  error.textContent = 'Name must be 3+ characters';
}
17

Building a Responsive Navbar

20 min
What you'll learn
  • Build a real navbar
  • Add mobile hamburger menu
  • Toggle with JavaScript

The navbar is on every website, and making it responsive is a rite of passage. On desktop, links show in a row. On mobile, they hide behind a hamburger button that toggles open. This combines Flexbox, media queries, and a tiny bit of JavaScript.

navbar.html
<nav class="navbar">
  <div class="logo">MySite</div>
  <button class="hamburger">☰</button>
  <ul class="nav-links">
    <li><a href="#">Home</a></li>
    <li><a href="#">About</a></li>
    <li><a href="#">Contact</a></li>
  </ul>
</nav>
Live Preview
browser — Building a Responsive Navbar
✓ Best Practice: Use aria-expanded on the hamburger for accessibility — screen readers need to know menu state.
Try it yourself

Add a CSS rule that hides .nav-links below 600px.

@media (max-width:600px) { .nav-links { display:none; } }
@media (max-width: 600px) {
  .nav-links { display: none; }
  .nav-links.open { display: flex; flex-direction: column; }
}
18

Building a Modal

18 min
What you'll learn
  • Create overlay modals
  • Open and close with JS
  • Handle backdrop clicks

Modals focus a user's attention on one task — signup, confirmation, details. The pattern: a fixed overlay covering the screen, a centered dialog, and JavaScript to open/close it. Clicking the backdrop or an X button closes it.

modal.js
const modal = document.querySelector('#modal');
const openBtn = document.querySelector('#open');
const closeBtn = document.querySelector('#close');

openBtn.addEventListener('click', () => modal.classList.add('open'));
closeBtn.addEventListener('click', () => modal.classList.remove('open'));
modal.addEventListener('click', (e) => {
  if (e.target === modal) modal.classList.remove('open');
});
Output
console
Clicking 'Open' shows the modal; clicking 'X' or the dark backdrop closes it.
💡 Tip: The e.target === modal check is the classic close-on-backdrop-click trick.
Try it yourself

Add Escape key support to close the modal.

document.addEventListener('keydown', e => { if (e.key === 'Escape') ... })
document.addEventListener('keydown', e => {
  if (e.key === 'Escape') modal.classList.remove('open');
});
19

Web Performance Basics

14 min
What you'll learn
  • Optimize images
  • Use lazy loading
  • Understand render blocking

Fast sites rank higher and keep users longer. Small wins: compress images, add loading='lazy' so off-screen images load later, and put scripts at the end of body. Performance isn't just for big companies — every millisecond counts for your users.

perf.html
<img
  src="hero.jpg"
  alt="Hero"
  loading="lazy"
  width="1200"
  height="600"
>
<script src="app.js" defer></script>
Output
console
A hero image that loads lazily with proper dimensions, and a script that doesn't block page rendering.
✓ Best Practice: Always set width and height on images — it prevents layout shift as they load.
Try it yourself

Add loading='lazy' to an image and defer to a script tag.

loading='lazy' on img, defer on script.
<img src="a.jpg" loading="lazy" alt="">
<script src="app.js" defer></script>
20

Capstone: Interactive Dashboard

40 min
What you'll learn
  • Combine Grid, fetch, and localStorage
  • Build a complete small app
  • Polish with animations

Your capstone: a dashboard with stat cards (Grid), a task list (localStorage persistence), and a button that fetches a random fact (fetch/async). It uses every intermediate skill — layout, state, async, and polish — in one real, working project.

dashboard.html
<!-- dashboard.html -->
<div class="dashboard">
  <header>My Dashboard</header>
  <div class="stats">
    <div class="stat">Tasks: <span id="taskCount">0</span></div>
    <div class="stat">Fact: <span id="fact">—</span></div>
  </div>
  <input id="taskInput" placeholder="Add task">
  <button id="addTask">Add</button>
  <button id="fetchFact">Get Random Fact</button>
  <ul id="taskList"></ul>
</div>
Live Preview
browser — Capstone: Interactive Dashboard
Tasks
5
Fact
Add task…
✓ Best Practice: This one project proves you can build real frontend apps — add it to your portfolio.
Try it yourself

Add a 'Clear All' button that removes every task.

list.innerHTML = ''; and clear localStorage.
clearBtn.addEventListener('click', () => {
  list.innerHTML = '';
  localStorage.removeItem('tasks');
});
You've completed all 20 intermediate lessons. Ready for advanced?

Continue to Web Development Advanced for performance, security, and full app architecture.

📱 Scan this QR code with your phone camera to instantly open this page.

Works on iOS, Android, and any modern device. No app installation required.

Account Verified!

Your email has been verified successfully.