# Introduction to Vue

Course: [Vue.js](https://www.devtutorials.ai/learn/vue) · Section: Vue Foundations
Source: https://www.devtutorials.ai/learn/vue/vue-foundations/introduction-to-vue

> What Vue is and why it was created, the progressive framework idea, the Vue ecosystem, Vue 2 vs Vue 3, Options API vs Composition API, CDN vs Vite, creating and running a project, its files, and your first app with createApp(), mount(), ref() and a click.

## Vue Introduction

- **Vue** is a JavaScript tool for building web pages that change when you click, type or load data.
- You write what the page should look like.
- Vue keeps the page up to date for you.
- In this lesson, you will set up Vue and build your first small app.

**Simple lesson:** Vue updates the page for you when your data changes.

### A Real-World Example

- Meera runs a small food stall called **Meera's Kitchen**.
- She wants a web page with a menu and an order counter.
- Each time a customer taps **Add order**, the number must go up.
- With plain JavaScript, she must find the number on the page and change it by hand.
- With Vue, she only changes the number in her code. Vue changes the page.

Press **▶ Run**, then click the button in the preview.

const orders = ref<number>(0);

function addOrder(): void {
    orders.value++;
}
</script>

<template>
    <h1>Meera's Kitchen</h1>
    <p>Orders today: {{ orders }}</p>
    <button @click="addOrder">Add order</button>
</template>
`,
    "main.ts": `import { createApp } from "vue";

createApp(App).mount("#app");
`,
  }}
/>

- **What happened:** the button adds 1 to `orders`.
- Vue saw the change and showed the new number at once.

### What You Will Learn

1. What Vue is and why people use it.
2. What a progressive framework means.
3. The difference between Vue 2 and Vue 3.
4. The two ways to write Vue code: Options API and Composition API.
5. Two ways to add Vue to a page: CDN and build tool.
6. How to create, run and build a Vue project.
7. What each file in a new project does.
8. How to start your first app with `createApp()` and `mount()`.
9. Which tools help you find problems.

## What Is Vue?

- **Vue** = a JavaScript framework for building user interfaces.
- **Framework** = ready-made code and rules that help you build apps faster.
- **User interface (UI)** = the part of an app you see and click.
- Vue is free and open source.
- It is said like the English word "view".

### Data Drives the Screen

- In Vue, you keep values like `orders` in your code. These values are called **state**.
- The template shows the state on the screen.
- When the state changes, Vue updates only the part of the page that uses it.
- Watch the animation: the code changes first, then Vue, then the screen.

<figure className="vue-fig ngc-fig">
<svg viewBox="0 0 640 200" role="img" aria-labelledby="fig-vue-reactive" style={{ width: "100%", maxWidth: 640, height: "auto" }}>
  <title id="fig-vue-reactive">Animation: the state orders changes from 0 to 1 to 2, a dot travels through Vue, and the screen shows the same number</title>
  <defs><marker id="vr-arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M0 0 L10 5 L0 10 z" style={{ fill: "var(--ngc-slate)" }} /></marker></defs>
  <rect x="20" y="45" width="170" height="110" rx="12" style={{ fill: "var(--ngc-blue-soft)", stroke: "var(--ngc-blue)", strokeWidth: 1.5 }} />
  <text x="105" y="72" textAnchor="middle" style={{ fill: "var(--ngc-blue)", fontFamily: "var(--sans)", fontSize: 13, fontWeight: 700 }}>Your code (state)</text>
  <g style={{ fontFamily: "var(--mono)", fontSize: 17, fill: "var(--ngc-blue)", fontWeight: 700 }}>
    <text x="105" y="115" textAnchor="middle"><animate attributeName="opacity" values="1;0;0;1" keyTimes="0;0.1;0.95;1" dur="6s" repeatCount="indefinite" />orders = 0</text>
    <text x="105" y="115" textAnchor="middle" opacity="0"><animate attributeName="opacity" values="0;1;1;0;0" keyTimes="0;0.1;0.5;0.55;1" dur="6s" repeatCount="indefinite" />orders = 1</text>
    <text x="105" y="115" textAnchor="middle" opacity="0"><animate attributeName="opacity" values="0;0;1;1;0" keyTimes="0;0.55;0.6;0.92;1" dur="6s" repeatCount="indefinite" />orders = 2</text>
  </g>
  <rect x="235" y="60" width="170" height="80" rx="12" style={{ fill: "var(--ngc-green-soft)", stroke: "var(--ngc-green)", strokeWidth: 1.5 }} />
  <text x="320" y="95" textAnchor="middle" style={{ fill: "var(--ngc-green)", fontFamily: "var(--sans)", fontSize: 18, fontWeight: 700 }}>Vue</text>
  <text x="320" y="117" textAnchor="middle" style={{ fill: "var(--ngc-green)", fontFamily: "var(--sans)", fontSize: 12 }}>watches the state</text>
  <rect x="450" y="35" width="170" height="130" rx="12" style={{ fill: "var(--ngc-win)", stroke: "var(--ngc-slate)", strokeWidth: 1.5 }} />
  <rect x="450" y="35" width="170" height="24" rx="12" style={{ fill: "var(--ngc-winbar)" }} />
  <text x="535" y="52" textAnchor="middle" style={{ fill: "var(--ngc-slate)", fontFamily: "var(--sans)", fontSize: 12 }}>Screen</text>
  <g style={{ fontFamily: "var(--sans)", fontSize: 18, fill: "var(--ngc-orange)", fontWeight: 700 }}>
    <text x="535" y="112" textAnchor="middle"><animate attributeName="opacity" values="1;1;0;0;1" keyTimes="0;0.3;0.31;0.97;1" dur="6s" repeatCount="indefinite" />Orders: 0</text>
    <text x="535" y="112" textAnchor="middle" opacity="0"><animate attributeName="opacity" values="0;0;1;1;0;0" keyTimes="0;0.3;0.31;0.8;0.81;1" dur="6s" repeatCount="indefinite" />Orders: 1</text>
    <text x="535" y="112" textAnchor="middle" opacity="0"><animate attributeName="opacity" values="0;0;1;1;0" keyTimes="0;0.8;0.81;0.95;1" dur="6s" repeatCount="indefinite" />Orders: 2</text>
  </g>
  <path d="M190 100 H232" style={{ stroke: "var(--ngc-slate)", strokeWidth: 2, fill: "none" }} markerEnd="url(#vr-arrow)" />
  <path d="M405 100 H447" style={{ stroke: "var(--ngc-slate)", strokeWidth: 2, fill: "none" }} markerEnd="url(#vr-arrow)" />
  <circle r="7" cy="100" style={{ fill: "var(--ngc-orange)" }}>
    <animate attributeName="cx" values="190;190;450;450;190;450;450" keyTimes="0;0.1;0.3;0.55;0.6;0.8;1" dur="6s" repeatCount="indefinite" />
    <animate attributeName="opacity" values="0;1;1;0;1;1;0" keyTimes="0;0.1;0.3;0.55;0.6;0.8;1" dur="6s" repeatCount="indefinite" />
  </circle>
  <text x="320" y="190" textAnchor="middle" style={{ fill: "var(--ngc-slate)", fontFamily: "var(--sans)", fontSize: 13 }}>You change the state. You never change the screen yourself.</text>
</svg>
<figcaption>The state changes first. Vue notices. The screen shows the new value.</figcaption>
</figure>

**State** = the values your app remembers, such as the number of orders. In Vue, you change the state, and Vue changes the screen.

**Simple lesson:** change the state, and Vue changes the screen.

## Why Vue Was Created

- Vue was made by **Evan You**. He used AngularJS in projects while working at Google.
- He wanted the useful parts of AngularJS in a smaller, simpler tool.
- The first version came out in **2014**.
- **Vue 3** came out in **2020**. It became the default version in 2022.
- Today, a core team and a large community look after Vue.

### Features of Vue

- **Easy start:** a page with one script tag is enough to try it.
- **Templates:** you write HTML with a few extra Vue rules.
- **Reactivity:** the screen updates when data changes.
- **Components:** you build the page from small, reusable parts.
- **Single-File Components:** the HTML, code and CSS of one part live in one `.vue` file.
- **Fast and small:** Vue only updates what changed.
- **TypeScript support:** Vue 3 itself is written in TypeScript.

**Simple lesson:** Vue was built to be simple to start and strong enough for big apps.

## A Progressive Framework

- **Progressive** = you can use a little of Vue, or all of it.
- You add more pieces only when your app needs them.
- Some tools ask you to learn everything on day one. Vue does not.
- Watch the layers build up, from one script tag to full websites.

<figure className="vue-fig ngc-fig">
<svg viewBox="0 0 640 250" role="img" aria-labelledby="fig-vue-layers" style={{ width: "100%", maxWidth: 640, height: "auto" }}>
  <title id="fig-vue-layers">Animation: four layers appear one by one. One script tag, then components, then Router and Pinia, then Nuxt</title>
  <g style={{ fontFamily: "var(--sans)", fontSize: 15, fontWeight: 700 }}>
    <g><rect x="60" y="190" width="520" height="46" rx="10" style={{ fill: "var(--ngc-green-soft)", stroke: "var(--ngc-green)", strokeWidth: 2 }} /><text x="320" y="219" textAnchor="middle" style={{ fill: "var(--ngc-green)" }}>1. One script tag: make part of a page interactive</text></g>
    <g opacity="0"><animate attributeName="opacity" values="0;0;1;1;0" keyTimes="0;0.2;0.25;0.92;1" dur="8s" repeatCount="indefinite" /><rect x="100" y="134" width="440" height="46" rx="10" style={{ fill: "var(--ngc-blue-soft)", stroke: "var(--ngc-blue)", strokeWidth: 2 }} /><text x="320" y="163" textAnchor="middle" style={{ fill: "var(--ngc-blue)" }}>2. Components: build the page from parts</text></g>
    <g opacity="0"><animate attributeName="opacity" values="0;0;1;1;0" keyTimes="0;0.42;0.47;0.92;1" dur="8s" repeatCount="indefinite" /><rect x="140" y="78" width="360" height="46" rx="10" style={{ fill: "var(--ngc-purple-soft)", stroke: "var(--ngc-purple)", strokeWidth: 2 }} /><text x="320" y="107" textAnchor="middle" style={{ fill: "var(--ngc-purple)" }}>3. Router + Pinia: pages and shared data</text></g>
    <g opacity="0"><animate attributeName="opacity" values="0;0;1;1;0" keyTimes="0;0.64;0.69;0.92;1" dur="8s" repeatCount="indefinite" /><rect x="180" y="22" width="280" height="46" rx="10" style={{ fill: "var(--ngc-orange-soft)", stroke: "var(--ngc-orange)", strokeWidth: 2 }} /><text x="320" y="51" textAnchor="middle" style={{ fill: "var(--ngc-orange)" }}>4. Nuxt: full websites</text></g>
  </g>
</svg>
<figcaption>Start with the bottom layer. Add a layer only when your app needs it.</figcaption>
</figure>

### The Vue Ecosystem

- **Ecosystem** = the official tools that work with Vue.
- **Vite:** starts and builds your project.
- **Vue Router:** moves between pages. You will learn it in **Vue Router Basics**.
- **Pinia:** keeps data that many parts share. You will learn it in **State Management with Pinia**.
- **Vue DevTools:** lets you look inside your running app.
- **Nuxt:** a bigger framework built on Vue for full websites. You will learn it in **Nuxt: Full-Stack Vue**.

**Simple lesson:** start small, and add tools only when you need them.

## Where Vue Is Used

- **Interactive pages:** search boxes, filters, order counters.
- **Single-Page Application (SPA)** = one page that changes its content without a full reload.
- **Progressive Web App (PWA)** = a website you can install and use like a phone app.
- **Dashboards:** charts and tables that update often.
- **Online shops:** product lists, carts and checkout.
- **Business apps:** big apps for offices and teams.

Before you start, you should know basic HTML, basic CSS and basic JavaScript: variables, functions, objects and arrays.

**Simple lesson:** Vue works for small widgets and for big apps.

## Vue 2 vs Vue 3

<div className="tscroll">

| Point | Vue 2 | Vue 3 |
|---|---|---|
| Released | 2016 | 2020 |
| Support | Ended on 31 December 2023 | Current and supported |
| Start an app | `new Vue(...)` | `createApp(...)` |
| Composition API | Added late, as an extra | Built in |
| TypeScript | Limited | Strong |
| Speed and size | Good | Faster and smaller |

</div>

- This course teaches **Vue 3** only.
- You may still see Vue 2 code in old projects and old blog posts.
- If you see `new Vue(...)`, it is Vue 2 code.

**Simple lesson:** learn Vue 3. Vue 2 no longer gets updates.

## Options API vs Composition API

- Vue gives you two styles to write the same component.
- **Options API** = you fill in named sections such as `data` and `methods`.
- **Composition API** = you write normal variables and functions inside `<script setup>`.
- Both styles make the same page.
- This course uses the **Composition API**. New Vue projects and the official docs use it.
- You will learn to read the older style in **Options API**.

Both boxes below build the same counter. Run each one.

    data() {
      return { orders: 0 };
    },
    methods: {
      addOrder(): void {
        this.orders++;
      },
    },
});
</script>

<template>
    <p>Orders: {{ orders }}</p>
    <button @click="addOrder">Add order</button>
</template>
`,
    "main.ts": `import { createApp } from "vue";

createApp(App).mount("#app");
`,
  }}
/>

- **What happened:** `this.orders++` changed the data, and the page updated.

const orders = ref<number>(0);

function addOrder(): void {
    orders.value++;
}
</script>

<template>
    <p>Orders: {{ orders }}</p>
    <button @click="addOrder">Add order</button>
</template>
`,
    "main.ts": `import { createApp } from "vue";

createApp(App).mount("#app");
`,
  }}
/>

- **What happened:** the same page, but the code uses plain variables and functions.
- There is no `this` to worry about.

**Simple lesson:** two styles, same result. This course uses the Composition API.

## Two Ways to Add Vue

### Using Vue from a CDN

- **CDN** = a website that hosts files you can link to.
- You add one `<script>` tag, and Vue is ready.
- No install is needed.
- It is good for trying Vue or adding it to an old page.

A whole CDN page looks like this:

```html
<!DOCTYPE html>
<html lang="en">
  <body>
    <div id="app">
      <h1>{{ shop }}</h1>
      <p>Today's special: {{ special }}</p>
    </div>

    <script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
    <script>
      Vue.createApp({
        setup() {
          const shop = "Meera's Kitchen";
          const special = "Masala dosa";
          return { shop, special };
        },
      }).mount("#app");
    </script>
  </body>
</html>
```

- The script tag creates a global `Vue` object.
- `Vue.createApp()` uses the HTML inside `#app` as the template.
- Run the same script below.

      <p>Today's special: {{ special }}</p>
    \`,
}).mount("#app");
`,
  }}
/>

On a real page, the `unpkg.com` link loads Vue from the internet. In this lab, the preview already has a fixed copy of Vue 3, so the box only holds the script. The template is passed as `template` because the box has no HTML file.

### Using Vue with a Build Tool

- **Build tool** = a program that prepares your code for the browser.
- Vue uses a build tool called **Vite** (said "veet", French for fast).
- It lets you write `.vue` files and TypeScript.
- It makes the final files small and fast.
- Real Vue apps use this way.

<figure className="vue-fig ngc-fig">
<svg viewBox="0 0 640 210" role="img" aria-labelledby="fig-vue-cdn-vite" style={{ width: "100%", maxWidth: 640, height: "auto" }}>
  <title id="fig-vue-cdn-vite">Animation: on the CDN path, index.html goes straight to the browser. On the build tool path, .vue and .ts files pass through Vite first</title>
  <defs><marker id="cv-arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M0 0 L10 5 L0 10 z" style={{ fill: "var(--ngc-slate)" }} /></marker></defs>
  <g style={{ fontFamily: "var(--sans)", fontSize: 14 }}>
    <text x="20" y="28" style={{ fill: "var(--ngc-green)", fontWeight: 700 }}>CDN</text>
    <rect x="20" y="40" width="160" height="46" rx="10" style={{ fill: "var(--ngc-win)", stroke: "var(--ngc-slate)", strokeWidth: 1.5 }} /><text x="100" y="68" textAnchor="middle" style={{ fill: "var(--ngc-slate)", fontFamily: "var(--mono)", fontSize: 13 }}>index.html</text>
    <path d="M180 63 H247" style={{ stroke: "var(--ngc-slate)", strokeWidth: 2 }} markerEnd="url(#cv-arrow)" />
    <rect x="250" y="40" width="160" height="46" rx="10" style={{ fill: "var(--ngc-win)", stroke: "var(--ngc-slate)", strokeWidth: 1.5 }} /><text x="330" y="68" textAnchor="middle" style={{ fill: "var(--ngc-slate)" }}>Browser</text>
    <path d="M410 63 H467" style={{ stroke: "var(--ngc-slate)", strokeWidth: 2 }} markerEnd="url(#cv-arrow)" />
    <rect x="470" y="40" width="150" height="46" rx="10" style={{ fill: "var(--ngc-green-soft)", stroke: "var(--ngc-green)", strokeWidth: 1.5 }} /><text x="545" y="68" textAnchor="middle" style={{ fill: "var(--ngc-green)", fontWeight: 700 }}>Page</text>
    <text x="20" y="130" style={{ fill: "var(--ngc-orange)", fontWeight: 700 }}>Build tool</text>
    <rect x="20" y="142" width="140" height="46" rx="10" style={{ fill: "var(--ngc-win)", stroke: "var(--ngc-slate)", strokeWidth: 1.5 }} /><text x="90" y="170" textAnchor="middle" style={{ fill: "var(--ngc-slate)", fontFamily: "var(--mono)", fontSize: 13 }}>.vue + .ts</text>
    <path d="M160 165 H197" style={{ stroke: "var(--ngc-slate)", strokeWidth: 2 }} markerEnd="url(#cv-arrow)" />
    <rect x="200" y="142" width="110" height="46" rx="10" style={{ fill: "var(--ngc-orange-soft)", stroke: "var(--ngc-orange)", strokeWidth: 1.5 }} /><text x="255" y="170" textAnchor="middle" style={{ fill: "var(--ngc-orange)", fontWeight: 700 }}>Vite</text>
    <path d="M310 165 H347" style={{ stroke: "var(--ngc-slate)", strokeWidth: 2 }} markerEnd="url(#cv-arrow)" />
    <rect x="350" y="142" width="100" height="46" rx="10" style={{ fill: "var(--ngc-win)", stroke: "var(--ngc-slate)", strokeWidth: 1.5 }} /><text x="400" y="170" textAnchor="middle" style={{ fill: "var(--ngc-slate)" }}>Browser</text>
    <path d="M450 165 H467" style={{ stroke: "var(--ngc-slate)", strokeWidth: 2 }} markerEnd="url(#cv-arrow)" />
    <rect x="470" y="142" width="150" height="46" rx="10" style={{ fill: "var(--ngc-green-soft)", stroke: "var(--ngc-green)", strokeWidth: 1.5 }} /><text x="545" y="170" textAnchor="middle" style={{ fill: "var(--ngc-green)", fontWeight: 700 }}>Page</text>
  </g>
  <circle r="7" cy="63" style={{ fill: "var(--ngc-green)" }}><animate attributeName="cx" values="100;545" dur="3s" repeatCount="indefinite" /></circle>
  <circle r="7" cy="165" style={{ fill: "var(--ngc-orange)" }}><animate attributeName="cx" values="90;255;255;545" keyTimes="0;0.35;0.55;1" dur="4s" repeatCount="indefinite" /></circle>
</svg>
<figcaption>The build tool adds one step. Vite turns `.vue` and `.ts` files into plain JavaScript the browser understands.</figcaption>
</figure>

<div className="tscroll">

| Point | CDN | Build tool (Vite) |
|---|---|---|
| Setup | One script tag | Install Node.js, create a project |
| `.vue` files | No | Yes |
| TypeScript | No | Yes |
| Best for | Trying Vue, small widgets | Real apps |

</div>

**Simple lesson:** use the CDN to try Vue. Use Vite for real projects.

## Creating a Vue Project

### Install Node.js

- **Node.js** = a program that runs JavaScript outside the browser. Vite needs it.
- **npm** = a tool that comes with Node.js. It downloads code packages.
- Download a recent **LTS** version from nodejs.org. LTS means it gets long-term fixes.
- Current Vite needs Node.js **20.19 or newer** (or 22.12+). An older Node gives a start-up error.
- Then check both versions in a terminal.

```bash
node -v
# v22.12.0
npm -v
# 10.9.0
```

- Each command prints a version number.
- Your numbers may be different. Any recent LTS version works.

### Create the Project with create-vue

- **create-vue** = the official tool that makes a new Vue project with Vite.
- It asks you a few questions, then creates the folder.

```bash
npm create vue@latest
```

It asks for a project name, then shows a list of features. Press **Space** to tick one and **Enter** when done. For this course:

- **Project name:** `meeras-kitchen`.
- **TypeScript:** tick it if you picked TypeScript in the top bar. Leave it if you picked JavaScript.
- **Router** and **Pinia:** leave them for now. You will add them later.
- **Vitest:** tick it. You will use it in **Testing Vue Apps**.
- **ESLint:** tick it. It warns you about mistakes.
- The exact questions can change between versions. If you see Yes/No questions instead, give the same answers.

### Install, Run and Build

```bash
cd meeras-kitchen
npm install      # 1. download the packages the project needs
npm run dev      # 2. start the dev server
#   ➜  Local:   http://localhost:5173/
npm run build    # 3. make the final files in the dist folder
```

- **npm install:** fills a `node_modules` folder with packages.
- **npm run dev:** starts a **dev server** = a small local website for testing. Open the link it prints.
- **npm run build:** makes small, fast files in `dist/`. You upload these to a real website.
- Stop the dev server with **Ctrl + C**.

Easy way to remember: **create** once, **install** once, **dev** every day, **build** when you publish.

**Simple lesson:** create, install, run. Build only when you want to publish.

## Project Structure

- A new project has a few folders and files.
- You will write most of your code inside `src/`.
- Click each file below to see what it does.

- Every box in this course is a small version of this project.
- Press the download button in a box to get it as a real project.

**Simple lesson:** `index.html` holds the empty box, `main` starts the app, and `App.vue` is what you see.

## Your First Vue App

### How a Vue App Starts

- **createApp()** = makes a new Vue app from a component.
- **Root component** = the first, top component. Here it is `App.vue`.
- **mount()** = puts the app inside a box on the HTML page.
- Watch the four steps light up in order.

<figure className="vue-fig ngc-fig">
<svg viewBox="0 0 640 170" role="img" aria-labelledby="fig-vue-boot" style={{ width: "100%", maxWidth: 640, height: "auto" }}>
  <title id="fig-vue-boot">Animation: the four start-up steps light up in order. index.html, main, createApp(App), mount('#app')</title>
  <g style={{ fontFamily: "var(--mono)", fontSize: 13 }}>
    <rect x="10" y="30" width="140" height="70" rx="10" style={{ fill: "var(--ngc-win)", stroke: "var(--ngc-slate)", strokeWidth: 1.5 }} />
    <rect x="10" y="30" width="140" height="70" rx="10" opacity="0" style={{ fill: "var(--ngc-green-soft)", stroke: "var(--ngc-green)", strokeWidth: 2.5 }}><animate attributeName="opacity" values="1;1;0;0" keyTimes="0;0.24;0.25;1" dur="8s" repeatCount="indefinite" /></rect>
    <text x="80" y="60" textAnchor="middle" style={{ fill: "var(--ngc-green)", fontWeight: 700 }}>index.html</text>
    <text x="80" y="82" textAnchor="middle" style={{ fill: "var(--ngc-slate)", fontSize: 11 }}>{'<div id="app">'}</text>
    <rect x="170" y="30" width="140" height="70" rx="10" style={{ fill: "var(--ngc-win)", stroke: "var(--ngc-slate)", strokeWidth: 1.5 }} />
    <rect x="170" y="30" width="140" height="70" rx="10" opacity="0" style={{ fill: "var(--ngc-blue-soft)", stroke: "var(--ngc-blue)", strokeWidth: 2.5 }}><animate attributeName="opacity" values="0;0;1;1;0;0" keyTimes="0;0.25;0.26;0.49;0.5;1" dur="8s" repeatCount="indefinite" /></rect>
    <text x="240" y="60" textAnchor="middle" style={{ fill: "var(--ngc-blue)", fontWeight: 700 }}>main</text>
    <text x="240" y="82" textAnchor="middle" style={{ fill: "var(--ngc-slate)", fontSize: 11 }}>runs first</text>
    <rect x="330" y="30" width="140" height="70" rx="10" style={{ fill: "var(--ngc-win)", stroke: "var(--ngc-slate)", strokeWidth: 1.5 }} />
    <rect x="330" y="30" width="140" height="70" rx="10" opacity="0" style={{ fill: "var(--ngc-purple-soft)", stroke: "var(--ngc-purple)", strokeWidth: 2.5 }}><animate attributeName="opacity" values="0;0;1;1;0;0" keyTimes="0;0.5;0.51;0.74;0.75;1" dur="8s" repeatCount="indefinite" /></rect>
    <text x="400" y="60" textAnchor="middle" style={{ fill: "var(--ngc-purple)", fontWeight: 700 }}>createApp(App)</text>
    <text x="400" y="82" textAnchor="middle" style={{ fill: "var(--ngc-slate)", fontSize: 11 }}>makes the app</text>
    <rect x="490" y="30" width="140" height="70" rx="10" style={{ fill: "var(--ngc-win)", stroke: "var(--ngc-slate)", strokeWidth: 1.5 }} />
    <rect x="490" y="30" width="140" height="70" rx="10" opacity="0" style={{ fill: "var(--ngc-orange-soft)", stroke: "var(--ngc-orange)", strokeWidth: 2.5 }}><animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.75;0.76;1" dur="8s" repeatCount="indefinite" /></rect>
    <text x="560" y="60" textAnchor="middle" style={{ fill: "var(--ngc-orange)", fontWeight: 700 }}>.mount("#app")</text>
    <text x="560" y="82" textAnchor="middle" style={{ fill: "var(--ngc-slate)", fontSize: 11 }}>shows it</text>
  </g>
  <path d="M150 65 H170 M310 65 H330 M470 65 H490" style={{ stroke: "var(--ngc-slate)", strokeWidth: 2 }} />
  <g style={{ fontFamily: "var(--sans)", fontSize: 13, fontWeight: 700 }}>
    <text x="320" y="140" textAnchor="middle" style={{ fill: "var(--ngc-green)" }}><animate attributeName="opacity" values="1;1;0;0" keyTimes="0;0.24;0.25;1" dur="8s" repeatCount="indefinite" />1. The browser opens index.html. It has an empty box.</text>
    <text x="320" y="140" textAnchor="middle" opacity="0" style={{ fill: "var(--ngc-blue)" }}><animate attributeName="opacity" values="0;0;1;1;0;0" keyTimes="0;0.25;0.26;0.49;0.5;1" dur="8s" repeatCount="indefinite" />2. index.html loads the main file. It runs first.</text>
    <text x="320" y="140" textAnchor="middle" opacity="0" style={{ fill: "var(--ngc-purple)" }}><animate attributeName="opacity" values="0;0;1;1;0;0" keyTimes="0;0.5;0.51;0.74;0.75;1" dur="8s" repeatCount="indefinite" />3. createApp(App) makes the app from App.vue.</text>
    <text x="320" y="140" textAnchor="middle" opacity="0" style={{ fill: "var(--ngc-orange)" }}><animate attributeName="opacity" values="0;0;1;1" keyTimes="0;0.75;0.76;1" dur="8s" repeatCount="indefinite" />4. mount("#app") shows the app inside the empty box.</text>
  </g>
</svg>
<figcaption>Every Vue 3 app starts with these four steps.</figcaption>
</figure>

### Hello World

- This project has two files: `App.vue` and the main file.
- Open each tab, then press **▶ Run**.

const message: string = "Hello, Vue!";
</script>

<template>
    <h1>{{ message }}</h1>
</template>
`,
    "main.ts": `import { createApp } from "vue";

createApp(App).mount("#app");
`,
  }}
/>

- **What happened:** the main file made the app from `App.vue` and mounted it in `#app`.
- `{{ message }}` showed the text.
- **`<template>`** = what the component shows on screen.
- **`<script setup>`** = the component's code. Every variable here can be used in the template.
- **`{{ }}`** = "show this value here". You will learn more in **Templates and Directives**.
- **`lang="ts"`** = this script is TypeScript. The JavaScript flavour leaves it out.

### Showing Reactive Data

- **ref()** = makes a value **reactive**. Vue watches it.
- In the script, read or change it with `.value`.
- In the template, just write its name. Vue adds `.value` for you.
- You will learn this fully in **Reactive State**.

const status = ref<string>("Kitchen is opening...");

setTimeout(() => {
    console.log("Before:", status.value);
    status.value = "Kitchen is open!";
    console.log("After:", status.value);
}, 2000);
</script>

<template>
    <h2>{{ status }}</h2>
</template>
`,
    "main.ts": `import { createApp } from "vue";

createApp(App).mount("#app");
`,
  }}
/>

- **What happened:** after 2 seconds, the code changed `status.value`.
- Vue updated the screen. The **Console** below the preview shows the old and new values.

### Handling a Button Click

- **@click** = "run this when the button is clicked".
- The function changes the state.
- Vue updates the page.

const orders = ref<number>(0);
const price: number = 40;

function addOrder(): void {
    orders.value++;
    console.log("Orders now:", orders.value);
}
</script>

<template>
    <p>Idlis ordered: {{ orders }}</p>
    <p>Total: ₹{{ orders * price }}</p>
    <button @click="addOrder">Add one idli</button>
</template>
`,
    "main.ts": `import { createApp } from "vue";

createApp(App).mount("#app");
`,
  }}
/>

- **What happened:** each click ran `addOrder()`.
- It changed `orders.value`, and both lines on the page updated.

**Simple lesson:** `createApp()` makes the app, `mount()` shows it, and `ref()` keeps the screen in sync.

## Development Tools

- **Vue DevTools** = a browser extension for Chrome and Firefox. It shows your components and their state.
- You can change a value in Vue DevTools and watch the page update.
- **Browser DevTools:** press **F12**. The Console tab shows errors and `console.log` output.
- **Hot Module Replacement (HMR)** = when you save a file, the page updates without a full reload.
- HMR keeps your state, so you do not lose what you typed.

In a real project, you open Vue DevTools from the browser. In this course, the **Console** under each preview shows your logs and Vue's warnings, like the browser Console. Lines that start with ⚠ are warnings to read.

**Simple lesson:** use Vue DevTools to see state, and the Console to see errors.

## TL;DR

- **Vue** = a JavaScript framework for building user interfaces.
- **Progressive** = use a little of Vue or all of it.
- **Vue 3** = the current version. Vue 2 support ended in 2023.
- **Composition API** = `<script setup>` with plain variables and functions. This course uses it.
- **CDN** = one script tag. **Vite** = the build tool for real projects.
- **Project steps** = `npm create vue@latest`, `npm install`, `npm run dev`, `npm run build`.
- **createApp(App)** = makes the app. **mount("#app")** = shows it in the page.
- **ref()** = a reactive value. Use `.value` in the script, not in the template.
- **@click** = run a function on a click.

## Common mistakes

<div className="tscroll">

| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
| Forgetting `mount()` | `createApp(App)` shows the app | Call `.mount("#app")` too | The page stays empty |
| Wrong mount id | Any id works | The id must match the `div` in `index.html` | Vue warns "Failed to mount app" and shows nothing |
| Plain variable for state | `let orders = 0` updates the page | Use `ref(0)` | The value changes, but the screen does not |
| No `.value` in the script | `orders++` works on a ref | Write `orders.value++` | The number never goes up |
| `.value` in the template | The template needs `.value` too | Write `{{ orders }}` | It works, but it is extra and confusing |
| Opening `dist/` to test | Built files are for testing | Test with `npm run dev` | No HMR, and old code shows |
| Copying Vue 2 code | All Vue code online is the same | Look out for `new Vue(...)` | Errors, because Vue 3 has no `new Vue` |

</div>

## Check Yourself

## Exercises

## What to Remember

- Vue keeps the screen in sync with your data.
- You can start with one script tag, but real apps use Vite.
- A new project has `index.html`, the main file and `App.vue` at its heart.
- `createApp()` plus `mount()` starts every Vue 3 app.
- `ref()` makes a value reactive. Change it with `.value` in the script.

Next: **Templates and Directives**
