Hook — 06 : 03 a.m., Cartagena ↔ San José pairing session
A dawn breeze drifted through my Colombian balcony when Sofía, coding before surf lessons in Costa Rica, sent a message: “I’ve copied the template from the docs, but nothing renders.” Her screen showed a single <div id="app"></div> and a JavaScript file full of errors. In ten shared minutes—still sipping my first espresso—we scaffolded a Vue 3 project with Vite, built a reusable <PriceCard> component, and watched it hot-reload in the browser. Her face lit up brighter than the Caribbean sunrise, and I remembered why component-based thinking clicks so powerfully. That remote rescue fuels today’s step-by-step journey from blank HTML to a living Vue.js component.


Why Components Are the Beating Heart of Modern Vue

Every Vue.js interface—from a tiny “Like” button to Netflix-scale dashboards—is stitched together from encapsulated pieces called components. They bundle template, logic, and style behind a custom tag, scale from static sites to SSR, and plug seamlessly into Storybook, Cypress, and design-system pipelines. Learning to author one is the first real threshold for any self-taught dev making the leap from HTML/CSS to modern reactive frameworks.


Setting Up the Playground

Start with Vite, the officially recommended build tool for Vue 3.

bashCopyEditnpm create vite@latest my-vue-playground -- --template vue
cd my-vue-playground
npm install
npm run dev

Your browser opens localhost:5173 showing the Vite + Vue starter. Replace the scaffold with a clean slate by editing App.vue.


Anatomy of a Single-File Component (SFC)

vueCopyEdit<!-- PriceCard.vue -->
<template>
  <article class="card">
    <h2>{{ title }}</h2>
    <p class="price">{{ formatted }}</p>
    <button @click="buy">Buy now</button>
  </article>
</template>

<script setup lang="ts">
import { computed, defineProps, defineEmits } from 'vue';

const props = defineProps<{ title: string; price: number }>();
const emit  = defineEmits<{ (e: 'purchase', price: number): void }>();

const formatted = computed(() => `$${props.price.toFixed(2)}`);
const buy = () => emit('purchase', props.price);
</script>

<style scoped>
.card { border: 1px solid #ddd; padding: 1rem; border-radius: .5rem; }
.price { font-size: 1.5rem; color: #047857; }
</style>

Inside a single file you have:


Mounting the Component in App.vue

vueCopyEdit<script setup lang="ts">
import PriceCard from './components/PriceCard.vue';
const purchased = (amount: number) =>
  alert(`Thanks for spending $${amount}!`);
</script>

<template>
  <PriceCard title="Premium Surf Wax" :price="9.99" @purchase="purchased" />
</template>

Hot-reload updates the DOM on save—no refresh required.


Options API Equivalent (For Comparison)

vueCopyEdit<template>
  <article class="card">
    <h2>{{ title }}</h2>
    <p class="price">{{ formatted }}</p>
    <button @click="$emit('purchase', price)">Buy now</button>
  </article>
</template>

<script lang="ts">
export default {
  name: 'PriceCardOptions',
  props: { title: String, price: Number },
  computed: {
    formatted() { return `$${(this.price as number).toFixed(2)}`; }
  },
};
</script>

Same output, but logic sits in an object of options rather than free functions. Newcomers often find Options easier to read; seniors gravitate to Composition for reuse and type inference.


Call-out Reference Table

Concept / ToolOne-liner purpose
<script setup>Zero-boilerplate Composition API syntax
defineProps / defineEmitsTypesafe props and events
Scoped stylesPrevent CSS bleed
Vite hot-module reloadInstant dev feedback
Options APIDeclarative object syntax alternative

Common Pitfalls and Easy Fixes


Remote-Work Insight

During a sprint in Panamá City, junior devs across five locales struggled to share reusable bits. We extracted a useCurrency() composable returning the formatted string and currency symbol based on locale. Components shrank, translations centralised, and coffee-shop Wi-Fi stayed happy because unused composables tree-shook out of the bundle.


Performance & Accessibility Checkpoints


Bringing the Component to Production

Build and preview:

bashCopyEditnpm run build
npm run preview

Vite outputs minified dist/ assets ready for Netlify, Vercel, or S3. Each SFC becomes a static module imported on demand—no extra configuration.


Key Takeaways

Crafting your first Vue.js component is less about memorizing API calls and more about embracing the mindset of encapsulated UI. Whether you choose Composition for feature-grouped logic or Options for declarative comfort, single-file components give you portable, testable building blocks. Layer composables, scoped styles, and typed props, and you’ll scale from small landing pages on Dominican Wi-Fi to enterprise dashboards served from São Paulo CDNs—with code that’s easy to read and fun to ship.

Questions, war stories, or surf-shop demos? Drop them below—I’ll answer between flights and late-night arepa sessions.

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x