Outcomes
HTML
JavaScript
CSS
Day 1
Day 1 · Module Overview

Basic Web Developmentwith Vue.js

A structured introduction to reactivity, frontend architecture, client-side routing, and API integration — using real Vue 3, HTML, and CSS.

Course Progress
Module 1Module 2Module 3Module 4
25%
Module 1

Learning Outcomes

What you'll understand and build by the end of Day 1.

1.1 — Understanding Reactivity in a Web App

Reactivity means the UI automatically updates when data changes — no manual DOM manipulation needed. Vue 3 achieves this through a proxy-based system that watches your data and re-renders only what changed.

The core idea is data binding: connect a variable to a piece of the UI, and they stay in sync at all times.

📦

ref()

Wraps a primitive into a reactive reference. Access via .value in JS.

🗂️

reactive()

Makes an entire object reactive. Properties tracked deeply.

🔁

computed()

Derives a value from reactive data. Recalculates automatically.

👁️

watch()

Runs a side effect when a reactive value changes.

⚠️ Reactivity Caveat

Destructuring a reactive() object loses reactivity. Use toRefs() to safely extract individual properties while keeping them reactive.

Live Demo — Reactivity with ref()Vue 3 · try it!
0

Computed double: 0 — updates automatically

Counter.vue
<script setup>
    import { ref, computed } from 'vue'

    // ref() creates a reactive number
    const count = ref(0)

    // computed() derives a value automatically
    const doubled = computed(() => count.value * 2)
</script>

<template>
    <p>Count: {{ count }}</p>
    <p>Double: {{ doubled }}</p>
    <button @click="count++">Increment</button>
    <button @click="count = 0">Reset</button>
</template>
🧑‍💻 Activities
  • Create a component using ref() to track a user's name input in real-time.
  • Use computed() to show the character count of the name.
  • Try destructuring a reactive() object — see what breaks, then fix it with toRefs().

1.2 — Developing a Frontend App with HTML, CSS & JavaScript

Vue is a progressive framework — you can drop it into a single HTML file, or build a full Single-File Component (SFC) app. An SFC (.vue file) keeps your template, script, and styles all in one place.

Vue's template syntax extends plain HTML with directives like v-for (loops), v-if (conditionals), and v-model (two-way binding).

Live Demo — v-model two-way bindingVue 3 · try it!

Hello, stranger! 👋

CardList.vue — Single-File Component
<script setup>
    // defineProps receives data from a parent component
    const props = defineProps({ items: Array })
</script>

<template>
  <div class="card-grid">
    <!-- v-for loops over an array -->
    <article v-for="item in items" :key="item.id">
      {{ item.title }}
    </article>
  </div>
</template>

<!-- scoped: styles only apply to this component -->
<style scoped>
.card-grid {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
}
</style>

1.3 — How Routing Works

In a Single-Page Application (SPA), the browser never fully reloads. Vue Router intercepts navigation and swaps out the visible component — giving users a fast, app-like experience.

You define routes (URL → component mappings), place <RouterView /> where the matched component should render, and use <RouterLink> for navigation instead of plain <a> tags.

router/index.js
// router/index.js
import { createRouter, createWebHistory } from 'vue-router'
import HomeView    from '../views/HomeView.vue'
import UserView    from '../views/UserView.vue'
import ProfileView from '../views/ProfileView.vue'

const routes = [
  { path: '/', component: HomeView },
  {
    path: '/user/:id',
    component: UserView,
    meta: { requiresAuth: true },
    children: [
      { path: 'profile', component: ProfileView }
    ]
  }
]

export default createRouter({
  history: createWebHistory(),
  routes
})

1.4 — Making API Requests with the Fetch API

The Fetch API is built into the browser — no library needed. It returns a Promise, so you use async/await to handle responses. Always manage loading and error states so users never see a blank screen.

Live Demo — Fetch a random jokeFetch API · try it!
DataFetch.vue — GET & POST patterns
<script setup>
import { ref } from 'vue'

const data    = ref(null)
const loading = ref(false)
const error   = ref(null)

// ── GET Request ──────────────────────────────────────
const fetchData = async () => {
  loading.value = true
  error.value   = null
  try {
    const res = await fetch('https://api.example.com/posts')
    if (!res.ok) throw new Error(`HTTP error: ${res.status}`)
    data.value = await res.json()
  } catch (err) {
    error.value = err.message
  } finally {
    loading.value = false
  }
}

// ── POST Request ─────────────────────────────────────
const submitForm = async (formData) => {
  const res = await fetch('/api/submit', {
    method:  'POST',
    headers: { 'Content-Type': 'application/json' },
    body:    JSON.stringify(formData)
  })
  return res.json()
}
</script>

<template>
  <div v-if="loading">Loading…</div>
  <div v-else-if="error">Error: {{ error }}</div>
  <ul v-else>
    <li v-for="post in data" :key="post.id">{{ post.title }}</li>
  </ul>
</template>
Refresher

HTML — HyperText Markup Language

The skeleton of every web page.

HTML is the standard language for structuring web content. Elements are written as tags, and browsers use them to know what kind of content to display — headings, paragraphs, images, links, and so on.

index.html — Minimal page
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8"/>
  <title>Page Title</title>
</head>
<body>
  <h1>This is a Heading</h1>
  <p>This is a paragraph.</p>
</body>
</html>
💡 How it renders

HTML renders top-to-bottom. <!DOCTYPE html> signals HTML5. <head> holds metadata (invisible to users). <body> holds visible content. Headings go from <h1> (most important) to <h6> (least important).

Page Structure

layout.html
<header>
  <h1>Company Name</h1>
  <nav>
    <a href="/">Home</a>
    <a href="/about">About</a>
    <a href="/contact">Contact</a>
  </nav>
</header>

<main>
  <h1>Page Title</h1>
  <p>Content goes here.</p>
</main>

<footer>
  <p>© 2025 Company Name</p>
</footer>

Common Tags

🛠️ Try It Yourself

Want to see these tags in action? Follow these simple steps:

  1. Copy any code snippet from the tabs below
  2. Open a text editor (Notepad, VS Code, or any editor you prefer)
  3. Create a new file and paste the code inside the <body> tags of a basic HTML file
  4. Save the file with a .html extension (e.g., my-page.html)
  5. Double-click the file to open it in your web browser

💡 Pro tip: Use the Copy button on each code block to grab the code instantly!

lists.html
<!-- Unordered list (bullet points) -->
<ul>
  <li>Coffee</li>
  <li>Tea</li>
  <li>Milk</li>
</ul>

<!-- Ordered list (numbered) -->
<ol>
  <li>Step one</li>
  <li>Step two</li>
  <li>Step three</li>
</ol>

HTML Attributes

Attributes add extra configuration to elements. They always appear inside the opening tag.

AttributeElementsDescription
idGlobalUnique identifier — used for CSS & JS targeting
classGlobalGroups elements for shared CSS styles
styleGlobalInline CSS (overrides external stylesheets)
hiddenGlobalHides element without removing it from the DOM
disabledbutton, input, select…Prevents the user from interacting with the element
srcimg, audio, video…URL of the embedded content
hrefa, linkURL of the linked resource
altimgFallback text for screen readers & broken images
loading="lazy"img, iframeDefers loading until element is near the viewport

DOM Events

Events are actions that happen in the browser — a click, a keypress, a form submission. You can listen for them and run code in response.

EventTriggered when…Common use
onclick / @clickUser clicks the elementButton actions, toggles
onsubmit / @submitForm is submittedValidate and send form data
onchange / @changeInput value changes (on blur)Dropdowns, checkboxes
oninput / @inputInput changes immediatelyReal-time search, char count
onkeydown / @keydownA keyboard key is pressedKeyboard shortcuts, validation
onmouseover / @mouseoverMouse enters the elementTooltips, hover highlights
onfocus / @focusElement receives focusHighlight active input field
onblur / @blurElement loses focusValidate field on exit
onscroll / @scrollUser scrolls the pageInfinite scroll, sticky nav
events.html — Keyboard listener example
<input
  type="text"
  placeholder="Press any key…"
  onkeydown="document.getElementById('out').textContent = 'Key: ' + event.key"
/>
<p id="out"></p>
Refresher

JavaScript — The Language of the Web

Add interactivity and dynamic behavior to your web pages.

What is JavaScript?

JavaScript is a programming language created by Brendan Eich in 1995. It was famously designed in about 10 days, which explains some of its quirks and design trade-offs.

The language was inspired by the Scheme programming language and was intended to be approachable, flexible, and easy to embed into web pages. One of its main highlights is its familiar syntax, which resembles Java and other C-like languages, making it easier for beginners to pick up.

JavaScript supports multiple programming paradigms:

  • Object-Oriented Programming (OOP)
  • Procedural Programming
  • Functional Programming (FP)

Because it supports functional programming, functions are first-class citizens. This means functions can be:

  • Stored in variables
  • Passed as arguments
  • Returned from other functions

In JavaScript, functions are treated just like any other value.

Where is JavaScript used?

JavaScript is most commonly used in web browsers. It was designed for scripting tasks such as manipulating elements in an HTML document, responding to user actions, and updating content dynamically without reloading the page.

A Simple Example

interactive.html
<html>
  <body>

    <p id="greeting">Hello</p>

    <button onclick="changeText()">Click me</button>

    <script>
      function changeText() {
        document.getElementById("greeting").innerText = "Hello World";
      }
    </script>

  </body>
</html>
🔍 What happens when the button is clicked?
  1. The button triggers changeText() — The onclick attribute tells the browser: "When this button is clicked, call the function named changeText."
  2. document represents the pagedocument is a global object provided by the browser. It represents the entire HTML page loaded in the tab and acts as the entry point to the DOM (Document Object Model) — the browser's in-memory tree of all elements on the page.
  3. getElementById("greeting") finds the element — This method searches the DOM and returns the element whose id matches "greeting". In this case, it returns the <p> element.
  4. .innerText = "Hello World" updates the page — Once you have a reference to the element, you can modify its properties. Changing innerText immediately updates the visible text on the page — no reload required.

Other things you can do with elements

  • element.innerHTML = "<span>Hello</span> World" — insert HTML
  • element.style.color = "red" — modify CSS styles
  • element.appendChild(newNode) — add child elements dynamically
⚠️ Why must IDs be unique?

getElementById is designed to return one element. If multiple elements share the same id, behavior becomes unpredictable. More importantly, the HTML specification states that duplicate IDs are invalid. CSS selectors, accessibility tools (like screen readers), and automated tests all rely on IDs being unique. Duplicate IDs can lead to subtle bugs that are very difficult to debug.

JavaScript Basics: Functions

Functions are one of the core building blocks of JavaScript.

A function is a reusable block of code that runs when it is called. There are two main steps:

  1. Declare the function
  2. Call the function
function-basics.js
function changeText(id) {
  // function body
  return "something";
}

A function declaration consists of:

  • The function body
  • Parameters
  • A return value

1. Function body

The code inside { } runs every time the function is called.

2. Parameters (arguments)

Parameters are inputs passed into a function.

parameters.js
function greet(name) {
  return "Hello, " + name;
}
// Calling greet("Aiman") assigns "Aiman" to name

// Multiple parameters:
function add(a, b) {
  return a + b;
}

If you pass fewer arguments than expected, the missing ones become undefined. JavaScript allows this silently, which can sometimes cause bugs if you're not careful.

3. Return value

The return statement sends a value back to the caller and immediately exits the function.

return.js
function add(a, b) {
  return a + b;
  console.log("this never runs"); // unreachable code
}

let result = add(3, 4); // 7
// If there is no return, the function returns undefined

Calling a function

calling.js
function greet(name) {
  return "Hello, " + name;
}

greet("Aiman");               // return value ignored
let msg = greet("Aiman");     // return value stored
console.log(msg);             // "Hello, Aiman"

// This is exactly what happens with onclick="changeText()" in HTML
// — the browser calls the function automatically when the event occurs.

Variables

Variables store data such as numbers, strings, arrays, and objects.

variables.js
let a = "Hello World";
console.log(a); // Hello World

// What's happening:
// let a = "Hello World" declares a variable and assigns a value to it.
// console.log(a) prints the value to the developer console.
🧮 Programming vs Mathematics

In mathematics: x = 5 means "x is always 5". In programming: x = 5; x = 10; means "store 5 in x, then later replace it with 10".

reassignment.js
let x = 5;
x = 10;
console.log(x); // 10

let vs const

JavaScript provides two main keywords for variables:

  • let — value can change
  • const — value cannot be reassigned
let-const.js
let score = 0;
score = 10; // allowed

const MAX_SCORE = 100;
MAX_SCORE = 200; // error: Assignment to constant variable
🧑‍💻 Activities
  • Create a function that takes a name and returns a personalized greeting.
  • Use getElementById to change the text of an element when a button is clicked.
  • Experiment with let vs const — try reassigning both and observe what happens.
Refresher

CSS — Cascading Style Sheets

Control how your HTML looks and feels.

CSS describes the presentation of HTML. You can attach styles via a linked .css file, a <style> block inside HTML, or directly via a style attribute on an element.

style.css — Linked stylesheet
/* Link in HTML: <link rel="stylesheet" href="style.css"> */

body {
  background-color: lightblue;
  font-family: sans-serif;
}

h1 {
  color: white;
  text-align: center;
}

/* Select by class */
.card {
  padding: 1rem;
  border: 1px solid #ccc;
  border-radius: 8px;
}

/* Select by id */
#main-title {
  font-size: 2rem;
  font-weight: bold;
}

CSS Selectors

selectors.css
/* All <p> elements */
p { color: red; }

/* Direct children only */
.parent > .child { color: blue; }

/* Hover state */
button:hover { background: green; }

/* First and last child */
li:first-child { font-weight: bold; }
li:last-child  { color: gray; }

/* Pseudo-elements — generated content */
.card::before {
  content: '★ ';
  color: gold;
}

/* CSS Custom Properties — define once, use everywhere */
:root {
  --primary:   #2d6a4f;
  --font-size: 16px;
}
h1 { color: var(--primary); }
p  { font-size: var(--font-size); }

Tailwind CSS

Tailwind is a utility-first CSS framework. Instead of writing custom CSS rules, you apply small pre-built classes directly in your HTML markup. This keeps styles co-located with your structure and speeds up development significantly.

tailwind-example.html
<!-- Traditional CSS approach -->
<div class="card">Hello</div>
<!-- Then write: .card { padding: 1rem; background: white; } -->

<!-- Tailwind approach: classes do the work directly -->
<div class="p-4 bg-white rounded shadow hover:shadow-lg transition">
  Hello
</div>

<!-- Responsive: md: applies on medium screens and up -->
<div class="text-sm md:text-base lg:text-lg">
  Responsive text
</div>

<!-- Dark mode support -->
<div class="bg-white dark:bg-gray-900 text-black dark:text-white">
  Adapts to system theme
</div>
📚 Learn More

Full Tailwind documentation at tailwindcss.com. Use the search to find any property — type "flex", "grid", "padding" and you'll immediately see the right utility class.

Day 1

Facilitation Guide

Tips for instructors and session leads.

🖐️ Hands-On First

Start each module with a 5-minute coding challenge before theory.

🌍 Real-World Context

Connect concepts to production examples.

👥 Peer Code Review

Swap screens for 3-minute feedback after exercises.

❓ Q&A Breaks

Allocate time after each outcome for questions.

⚠️ Anticipate Pitfalls

Watch for reactivity loss, router mismatches, CORS errors.

💬 Feedback Loop

End sessions with "What will you build tomorrow?"

Quick Start Commands

terminal
# Create a new Vite project (official scaffolding)
$ npm create vite@latest my-app
# Select: Vue + JavaScript

# Install dependencies and start dev server
$ cd my-app && npm install && npm run dev
# → http://localhost:5173

# Install tailwindcss and @tailwindcss/vite via npm.

$ npm install tailwindcss @tailwindcss/vite


Configure the Vite plugin

vite.config.js
#Add the @tailwindcss/vite plugin to your Vite configuration.

import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'

export default defineConfig({
  plugins: [
    tailwindcss(),
  ],
})


Import Tailwind CSS

style.css
#Add an @import to your CSS file that imports Tailwind CSS.

@import "tailwindcss";

📖 Resources

Vue 3 Docs: vuejs.org/guide  · Vue Router: router.vuejs.org  · Tailwind CSS: tailwindcss.com  · MDN Web Docs: developer.mozilla.org