Riad Kilani
  • Bio
  • Portfolio
  • Blog
  • Contact
  • Accessibility
  • Case Studies
  • CSS
  • Design
  • Front-End
  • HTML
  • JavaScript
  • News
  • Productivity
  • Random Thoughts
  • SEO
  • Themes
  • Trends
  • Tutorials
  • TypeScript
  • TypeSCript From The Ground Up
  • UX Engineering
  • Web Development
  • Wordpress
Home » Front-End » Up and Running with Vue.js (Fast Start for 2025)

Up and Running with Vue.js (Fast Start for 2025)

August 29, 2025
Vue.js logo next to a minimal dashboard UI on a light abstract background with the headline “Up and Running with Vue.js.”

Related reads: Emmet Tips & Tricks for Beginners, Exploring New CSS Features in 2025, Vue.js: 10 Tips & Tricks, and Understanding JavaScript Scope: A Beginner’s Guide.

What we’ll cover (quick overview)

  • What Vue is and when to use it (Vue Docs)
  • Two fast start paths: CDN and Vite (Vite Docs)
  • Reactivity + Composition API mental model (Vue Docs)
  • Components, props & emits
  • Routing with Vue Router (Vue Router Docs)
  • Global state with Pinia (Pinia Docs)
  • Fetching data (loading/error patterns) — pair with JavaScript Promise: What It Is and How to Use It
  • Forms & v-model
  • Devtools, build & deploy (including WordPress) — see Building a Block Theme in 2025
  • Common pitfalls & next steps

What is Vue—and when should you use it?

Vue is a progressive framework for building interactive UIs. It’s small, fast, and scales from a single widget to full apps. Reach for Vue when you need rich interactivity (filters, tabs, forms, dashboards) without heavy ceremony. (Overview: Vue Docs)

Two quick ways to start (CDN vs. Vite)

Option A — One-file demo via CDN (fastest)

Reference: Vue Docs

<div id="app">
  <h2>{{ title }}</h2>
  <button @click="count++">Clicked {{ count }} times</button>
</div>

<script type="module">
  import { createApp, ref } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js'
  createApp({
    setup() {
      const title = ref('Hello Vue 👋')
      const count = ref(0)
      return { title, count }
    }
  }).mount('#app')
</script>

Option B — Vite + Single File Components (production-ready)

Starter: Vite Docs

# Node 18+ recommended
npm create vite@latest my-vue-app -- --template vue
cd my-vue-app
npm install
npm run dev

This gives you Single File Components (.vue), hot reload, TypeScript support, and a simple build step.

Core mental model: reactivity + the Composition API

Concepts: Composition API FAQ

<script setup>
import { ref, computed, watch } from 'vue'
const count = ref(0)
const doubled = computed(() => count.value * 2)
watch(count, n => console.log('count changed to', n))
</script>

<template>
  <button @click="count++">
    {{ count }} (x2 = {{ doubled }})
  </button>
</template>

Tips: Use ref for primitives, reactive() for objects, prefer computed over watch for derivations.

Components, props & emits (parent/child flow)

Guide: Props & one-way data flow

Child component

<!-- src/components/TodoItem.vue -->
<script setup>
import { defineProps, defineEmits } from 'vue'
const props = defineProps({ item: Object })
const emit = defineEmits(['toggle'])
</script>

<template>
  <label>
    <input type="checkbox" :checked="item.done" @change="emit('toggle', item.id)" />
    <span :style="{ textDecoration: item.done ? 'line-through' : 'none' }">{{ item.title }}</span>
  </label>
</template>

Parent component

<script setup>
import { reactive } from 'vue'
import TodoItem from './TodoItem.vue'

const state = reactive({
  todos: [
    { id: 1, title: 'Learn Vue', done: false },
    { id: 2, title: 'Ship feature', done: true }
  ]
})

function toggle(id){
  const t = state.todos.find(t => t.id === id)
  t.done = !t.done
}
</script>

<template>
  <TodoItem v-for="t in state.todos" :key="t.id" :item="t" @toggle="toggle" />
</template>

Routing with Vue Router

Docs: Vue Router

npm i vue-router
// src/router.js
import { createRouter, createWebHistory } from 'vue-router'
import Home from './pages/Home.vue'
import About from './pages/About.vue'

export const router = createRouter({
  history: createWebHistory(),
  routes: [
    { path: '/', component: Home },
    { path: '/about', component: About }
  ]
})
// src/main.js
import { createApp } from 'vue'
import { router } from './router'
import App from './App.vue'
createApp(App).use(router).mount('#app')

Global state with Pinia (lightweight & type-friendly)

Docs: Pinia

npm i pinia
// src/stores/useTodos.js
import { defineStore } from 'pinia'
export const useTodos = defineStore('todos', {
  state: () => ({ items: [] }),
  actions: {
    add(title){ this.items.push({ id: Date.now(), title, done: false }) }
  },
  getters: {
    remaining: (s) => s.items.filter(i => !i.done).length
  }
})

Fetching data (loading/error patterns)

Brush up on async flows with JavaScript Promise: What It Is and How to Use It—it pairs nicely with the pattern below.

<script setup>
import { ref, onMounted } from 'vue'
const users = ref([])
const loading = ref(false)
const error = ref(null)

onMounted(async () => {
  loading.value = true
  try {
    const res = await fetch('https://jsonplaceholder.typicode.com/users')
    if (!res.ok) throw new Error('Network error')
    users.value = await res.json()
  } catch (e) {
    error.value = e.message
  } finally {
    loading.value = false
  }
})
</script>

<template>
  <p v-if="loading">Loading…</p>
  <p v-else-if="error">Error: {{ error }}</p>
  <ul v-else>
    <li v-for="u in users" :key="u.id">{{ u.name }}</li>
  </ul>
</template>

Forms & v-model

Guide: Forms

<script setup>
import { ref } from 'vue'
const form = ref({ name: '', newsletter: false })
</script>

<template>
  <input v-model="form.name" placeholder="Your name" />
  <label><input type="checkbox" v-model="form.newsletter" /> Subscribe</label>
  <pre>{{ form }}</pre>
</template>

Devtools, build & deploy (including WordPress)

  • Devtools: Install the Vue Devtools browser extension to inspect component state.
  • Build: npm run build (Vite build)
  • WordPress: Great for mounting Vue widgets in themes/plugins. For a WordPress-first path, see Building a Block Theme in 2025.

Enqueue your compiled script and mount point

// functions.php (theme) or main plugin file
add_action('wp_enqueue_scripts', function () {
  wp_enqueue_script(
    'my-vue-app',
    get_stylesheet_directory_uri() . '/assets/my-vue-app/dist/assets/index.js',
    array(), null, true
  );
});
<div id="my-vue-app"></div>

Common pitfalls (and how to avoid them)

  • Missing :key in v-for (use stable IDs). List rendering: Vue Docs
  • Overusing watch—prefer computed for derivations. Computed
  • Mutating props directly—emit events or use a store. Props are read-only
  • Performance—lazy-load routes & split chunks. Lazy loading

Next steps

  • Build a tiny widget first, then layer in Router and Pinia.
  • Revisit fundamentals with Understanding JavaScript Scope and modern styling in Exploring New CSS Features in 2025.
  • Speed up authoring with Emmet Tips & Tricks for Beginners. When you’re ready for more Vue patterns, read Vue.js: 10 Tips & Tricks.

Bonus: quick starter scaffold

npm create vite@latest vue-starter -- --template vue
cd vue-starter && npm i && npm run dev

src/App.vue

<script setup>
import { ref } from 'vue'
const name = ref('Riad')
</script>

<template>
  <main>
    <h1>Vue Starter</h1>
    <input v-model="name" />
    <p>Hello, {{ name }}</p>
  </main>
</template>

<style scoped>
main { max-width: 720px; margin: 3rem auto; font: 16px/1.6 system-ui, sans-serif; }
input { padding: .5rem .75rem; }
</style>

src/main.js

import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

← Previous Post 10 Vue.js Tips & Tricks I Wish I Knew Sooner (Vue 3 Edition)
Next Post → JavaScript Reducers: What They Are and Why Use Them

Categories

  • Accessibility
  • Case Studies
  • CSS
  • Design
  • Front-End
  • HTML
  • JavaScript
  • News
  • Productivity
  • Random Thoughts
  • SEO
  • Themes
  • Trends
  • Tutorials
  • TypeScript
  • TypeSCript From The Ground Up
  • UX Engineering
  • Web Development
  • Wordpress

Recent Posts

  • Native CSS Is Quietly Replacing Sass, But It Isn’t Replacing the “Need” for Sass
  • Everyday Types Explained (From the Ground Up)
  • 2026 CSS Features You Must Know (Shipped Late 2025–Now)
  • 60 JavaScript Projects in 60 Days
  • JavaScript vs TypeScript: What Actually Changes

Tags

accessibility accessible web design ADA compliance async components Career Journey cascade layers code splitting composables composition api computed properties container queries css Design Inspiration Design Systems disability access File Organization Front-End Development Frontend frontend development immutability javascript JavaScript reducers lazy loading Material Design Modern CSS performance Personal Growth react React useReducer Redux Resume screen readers seo Suspense Teleport TypeScript UI/UX UI Engineering UX UX Engineering Vue Router WCAG web accessibility Web Development Web Performance

Riad Kilani Front-End Developer

© 2026 Riad Kilani. All rights reserved.