vuenuxttutorialportfolio

Build a Vue.js Portfolio Site with AI

Create a beautiful portfolio website using Vue.js and Nuxt 4 with AI. From hero section to contact form — generated from a single description in LoomCode AI.

LoomCode AI Team12 min read

Why Vue for a Portfolio?

Vue.js (powered by Nuxt 4) offers the perfect balance of simplicity and power for portfolio sites. With the Composition API, TypeScript support, and Tailwind CSS, you get a modern, performant site. With LoomCode AI, you get it in seconds.

Vue's single-file component model keeps your template, logic, and styles co-located in one .vue file. For a portfolio, this means each section — hero, about, projects — lives in its own self-contained component that is straightforward to customize after generation. There is no context-switching between separate HTML, CSS, and JS files.

Nuxt 4 builds on top of Vue to provide server-side rendering, file-based routing, and automatic component imports out of the box. These features matter for portfolios because recruiters and potential clients need your site to load fast and rank well in search results.

Vue vs React for Portfolios

Both Vue and React can build excellent portfolio sites, but Vue has several practical advantages that make it a stronger choice for this use case. For a detailed side-by-side breakdown, see our React vs Vue comparison.

Template syntax is more approachable. Vue's HTML-based templates are closer to standard markup than JSX. If you are a designer who writes HTML and CSS but is not deeply familiar with JavaScript patterns, Vue templates will feel natural. Conditional rendering uses v-if and v-show directives directly on elements rather than ternary expressions embedded in JSX. List rendering uses v-for instead of .map() chains. The result is templates that read more like the final HTML output.

Nuxt 4's auto-imports reduce boilerplate. In a React project with Next.js, you still import useState, useEffect, and every utility at the top of each file. Nuxt 4 auto-imports Vue's Composition API functions, your components, and your composables. A typical Vue portfolio component starts with the logic immediately — no import block stretching twenty lines before you reach the actual code.

Vue's transition system is built-in. Adding entrance animations, page transitions, or list animations in Vue requires only the <Transition> and <TransitionGroup> wrapper components that ship with the framework. In React, you typically reach for a third-party library like framer-motion or react-transition-group. For a portfolio where visual polish matters, having transitions as a first-class feature saves time and reduces bundle size.

SSG with Nuxt for zero-JS landing pages. Running nuxi generate produces fully static HTML files that can be served from any CDN. With Nuxt's island architecture and selective hydration, you can ship pages with zero client-side JavaScript where interactivity is not needed. A portfolio landing page that loads as pure HTML and CSS will score near-perfect on Lighthouse and feel instant to visitors on any connection.

What We'll Build

A developer portfolio with:

  • Hero section with animated intro
  • About section with skills grid
  • Projects showcase with image cards
  • Experience timeline
  • Contact form
  • Responsive design with dark mode
  • Smooth scroll navigation

The Prompt

Select the Vue.js template on LoomCode AI and enter:

Build a developer portfolio website:
- Hero section with name, title "Full-Stack Developer", short bio, and call-to-action buttons (View Work, Contact Me)
- About section with a skills grid showing: JavaScript, TypeScript, Vue, React, Node.js, Python, Docker, AWS
- Projects section with 4 project cards (image placeholder, title, description, tech stack tags, GitHub/live links)
- Experience section as a vertical timeline with 3 entries
- Contact section with a form (name, email, message) and social links
- Sticky navbar with smooth scroll to sections
- Dark mode toggle
- Use Tailwind CSS for styling, make it visually impressive with gradients and animations

What You Get

LoomCode AI generates a complete Nuxt 4 application:

App Structure

app/
  app.vue          — Root component with layout
  pages/
    index.vue      — Main portfolio page with all sections
  components/
    Hero.vue       — Animated hero section
    About.vue      — Skills grid component
    Projects.vue   — Project cards with hover effects
    Experience.vue — Timeline component
    Contact.vue    — Form with validation
    Navbar.vue     — Sticky navigation

Key Features Generated

Smooth Scroll Navigation — The navbar links use scrollIntoView with smooth behavior. Active section tracking highlights the current nav item.

Responsive Grid — Skills display in a responsive grid that adapts from 2 columns on mobile to 4 on desktop.

Project Cards — Hover effects reveal project descriptions and tech stack tags. Each card links to GitHub and live demo URLs.

Dark Mode — A toggle in the navbar switches between light and dark themes using Tailwind's dark mode classes.

Key Generated Code Patterns

The AI generates Vue components using modern patterns that are clean, type-safe, and performant. Here is a representative example of a scroll-triggered animation component:

<script setup lang="ts">
import { ref, onMounted } from 'vue'

const isVisible = ref(false)
const sectionRef = ref<HTMLElement>()

onMounted(() => {
  const observer = new IntersectionObserver(
    ([entry]) => { isVisible.value = entry.isIntersecting },
    { threshold: 0.1 }
  )
  if (sectionRef.value) observer.observe(sectionRef.value)
})
</script>

<template>
  <section ref="sectionRef"
    :class="['transition-all duration-700', isVisible ? 'opacity-100 translate-y-0' : 'opacity-0 translate-y-8']">
    <slot />
  </section>
</template>

This pattern demonstrates several core Vue concepts working together:

Composition API with <script setup> — The <script setup> syntax is the recommended way to write Vue components. It automatically exposes all top-level bindings to the template, eliminating the need for an explicit return statement or defineComponent wrapper. The result is less code and stronger type inference.

Reactive refsref() creates reactive state. When isVisible.value changes from false to true, Vue automatically re-evaluates the class binding in the template. There is no manual DOM manipulation and no need to call setState or trigger a re-render — reactivity is granular and handled at the variable level.

IntersectionObserver for scroll animations — Rather than listening to scroll events (which fire hundreds of times per second), the IntersectionObserver API efficiently detects when an element enters the viewport. The observer is set up in onMounted to ensure the DOM ref is available. With a threshold of 0.1, the animation triggers when just 10% of the section is visible.

Clean template syntax — The :class binding uses an array with a ternary expression to toggle Tailwind utility classes. The <slot /> element lets this component wrap any content, making it a reusable animation wrapper you can apply to every section of your portfolio.

This same pattern is applied across the generated portfolio — the hero section fades in on load, project cards slide up as you scroll, and the experience timeline entries appear sequentially.

Customization Prompts

After the initial generation, personalize it:

  • "Replace the placeholder name with John Doe and update the bio"
  • "Add a blog section that shows 3 recent article cards"
  • "Add a testimonials carousel section"
  • "Make the hero section full-screen with a particle background"
  • "Add page transition animations between sections"

Personalizing Your Portfolio

Generic portfolio templates look generic. The real value of AI-assisted generation is rapid iteration — you can reshape the output with follow-up prompts until every detail reflects your actual identity and goals.

Start with your personal information. Give the AI a complete context so it can replace every placeholder in a single pass:

Replace all placeholder data with: Name: Jane Smith, Title: Frontend Developer,
Bio: I build accessible, performant web applications with Vue and TypeScript.
Based in Portland. Previously at Stripe and Shopify. Update the hero section,
navbar, page title, and footer to reflect this.

Next, add a content section that demonstrates your writing and thinking:

Add a blog section that fetches posts from a /content directory using
Nuxt Content. Display the 3 most recent posts as cards with title, date,
excerpt, and reading time. Link each card to its full post page.

Implement theme switching that respects user preferences:

Add a dark/light mode toggle with system preference detection. Use
useColorMode() from @nuxtjs/color-mode. Persist the choice in localStorage.
Apply the toggle in the navbar with a sun/moon icon.

Finally, add visual polish with route transitions:

Add smooth page transition animations between routes. Use Vue's built-in
Transition component in app.vue with a fade-and-slide effect. Duration
should be 300ms with ease-in-out timing.

Each of these prompts builds on the existing generated code. The AI understands the component structure it created and modifies the right files without breaking the layout or navigation.

SEO Optimization for Your Vue Portfolio

A portfolio that cannot be found in search results will not bring opportunities. Nuxt 4 provides strong SEO foundations, but you need to configure them properly.

Server-side rendering gives you crawlable content. Nuxt 4 renders your pages on the server by default. When Googlebot requests your portfolio, it receives fully rendered HTML with all your text content, project descriptions, and skill listings immediately available. Client-side-only React apps require the crawler to execute JavaScript, which some search engines handle inconsistently.

Add meta tags with useHead(). Nuxt's useHead() composable lets you set page-level meta information reactively. For your portfolio's main page, set a descriptive title, a meta description that includes your name and specialization, and Open Graph tags so your site looks polished when shared on LinkedIn or Twitter:

<script setup lang="ts">
useHead({
  title: 'Jane Smith — Frontend Developer',
  meta: [
    { name: 'description', content: 'Frontend developer specializing in Vue.js and TypeScript. View my projects, experience, and get in touch.' },
    { property: 'og:title', content: 'Jane Smith — Frontend Developer' },
    { property: 'og:description', content: 'Portfolio showcasing Vue.js, TypeScript, and web performance projects.' },
    { property: 'og:image', content: 'https://janesmith.dev/og-image.png' },
  ],
})
</script>

Generate a sitemap. Install @nuxtjs/sitemap and add it to your Nuxt config. The module automatically generates a sitemap.xml that includes all your routes. If you add a blog section later, new posts are included automatically. Submit your sitemap in Google Search Console to accelerate indexing.

Optimize images with Nuxt Image. The @nuxt/image module provides the <NuxtImg> component that automatically generates responsive sizes, converts to modern formats like WebP, and lazy-loads images below the fold. For your project screenshots and profile photo, replacing standard <img> tags with <NuxtImg> can cut image payload by 40-60% with no visual quality loss.

Performance Tips

A fast portfolio signals competence. If you claim to be a skilled developer but your own site takes four seconds to load, visitors will notice the contradiction.

Lazy load images. Use the loading="lazy" attribute on all images below the fold. If you are using Nuxt Image, this is the default behavior. For the hero section image or profile photo that is visible on initial load, use loading="eager" instead to avoid a flash of empty space.

Code split with dynamic imports. Sections of your portfolio that are far down the page do not need to load immediately. Use Vue's defineAsyncComponent to defer loading heavy components like a project gallery with image lightboxes or an interactive contact map:

<script setup lang="ts">
const HeavyProjectGallery = defineAsyncComponent(
  () => import('~/components/ProjectGallery.vue')
)
</script>

The component will only be fetched when it is about to render, reducing your initial JavaScript bundle.

Use SSG for static hosting. If your portfolio content does not change frequently, run nuxi generate to produce a fully static site. The output is a directory of HTML, CSS, and JS files that you can deploy to any CDN — Vercel, Netlify, Cloudflare Pages, or even GitHub Pages. Static files are served from edge locations worldwide with response times under 50ms.

Optimize for Lighthouse. After deploying, run a Lighthouse audit in Chrome DevTools. Target 90+ on all four categories. Common fixes for portfolio sites include: setting explicit width and height on images to prevent layout shift, preloading your primary font file, ensuring sufficient color contrast in both light and dark modes, and adding aria-label attributes to icon-only buttons like the dark mode toggle.

Vue.js Tips for Better AI Output

  1. Mention Composition API: The AI uses <script setup lang="ts"> by default, but mentioning it ensures proper patterns
  2. Specify component names: "Create a Hero.vue component" gives you better file organization
  3. Reference Tailwind utilities: "Use gradient text", "Add hover scale effect" translate directly to Tailwind classes
  4. Ask for animations: "Fade in on scroll", "Slide in from left" — the AI generates intersection observer-based animations

Comparing Portfolio Frameworks

For in-depth comparisons of each framework pair, see the full framework comparisons. You can also explore the step-by-step guide for building a portfolio with Vue.

| Feature | Vue/Nuxt | Next.js | React | |---------|----------|---------|-------| | SSR/SSG | Built-in | Built-in | Needs setup | | File-based routing | Yes | Yes | No | | Tailwind integration | Excellent | Excellent | Good | | Learning curve | Low | Medium | Medium | | Best for portfolios | Excellent | Excellent | Good |

FAQ

Q: Can I add a blog to my Vue portfolio?

Yes! Ask the AI to "Add a blog section using Nuxt Content" or simply "Add a blog page with markdown support." Nuxt's content module makes this seamless.

Q: Is the generated portfolio SEO-friendly?

Nuxt 4 provides SSR by default, which means your portfolio is fully crawlable by search engines. The AI also generates proper meta tags and semantic HTML.

Q: How do I deploy the Vue portfolio?

Copy the code and deploy to Vercel, Netlify, or any Node.js hosting. Nuxt supports static generation (nuxi generate) for hosting on any static CDN.

Q: What if I want to add a custom domain?

All major hosting platforms support custom domains. On Vercel or Netlify, add your domain in the project settings and update your DNS records. For a portfolio, a clean domain like janesmith.dev is worth the small annual cost — it reinforces your professional brand.

Q: Can I use this with a CMS for project data?

Yes. Ask the AI to "Fetch project data from a JSON file" or "Connect to a headless CMS like Sanity or Storyblok." Nuxt's data fetching layer with useFetch and useAsyncData makes it straightforward to pull content from any API at build time or on each request.

Ready to build your app?

Describe your idea and get a working app in seconds with LoomCode AI.

Start Building