scaffolding-vue-components
Vue Component Architect
When to use this skill
- User asks to create a new Vue component
- User wants component scaffolding with tests and stories
- User mentions Nuxt component creation
- User asks for TypeScript props definitions
- User wants CSS modules or scoped styles setup
Workflow
- Determine component name and location
- Detect project conventions (Nuxt vs Vue, styling approach)
- Generate component file with Composition API
- Create CSS module or scoped styles
- Generate Vitest test file
- Create Storybook story
- Export from index if barrel pattern used
Instructions
Step 1: Determine Component Details
Gather from user:
- Component name (PascalCase)
- Location:
src/components/,components/, or feature folder - Type: presentational, container, layout, or page component
Derive file paths:
src/components/Button/
├── Button.vue
├── Button.test.ts
├── Button.stories.ts
└── index.ts
Step 2: Detect Project Conventions
Vue vs Nuxt:
ls nuxt.config.* 2>/dev/null && echo "Nuxt project"
ls vite.config.* vue.config.* 2>/dev/null && echo "Vue project"
Styling approach:
grep -l "module.css\|module.scss" src/**/*.vue 2>/dev/null | head -1 && echo "CSS Modules"
grep -l "<style scoped" src/**/*.vue 2>/dev/null | head -1 && echo "Scoped styles"
npm ls tailwindcss 2>/dev/null && echo "Tailwind CSS"
State management:
npm ls pinia vuex 2>/dev/null
Test framework:
npm ls vitest @vue/test-utils 2>/dev/null
Step 3: Generate Component File
Use the standard Composition API structure:
<script setup lang="ts">with typed props and emitswithDefaults(defineProps<Props>(), { ... })for defaultsdefineEmits<{ event: [payload] }>()for typed events<style module>with design tokens
See component-templates.md for full templates including:
- Standard component with variants
- Component with composables
- Pinia store integration
Step 4: Generate Test File
Use Vitest with Vue Test Utils:
import { describe, it, expect } from "vitest";
import { mount } from "@vue/test-utils";
import ComponentName from "./ComponentName.vue";
describe("ComponentName", () => {
it("renders slot content", () => {
const wrapper = mount(ComponentName, {
slots: { default: "Hello" },
});
expect(wrapper.text()).toContain("Hello");
});
it("emits click when not disabled", async () => {
const wrapper = mount(ComponentName);
await wrapper.trigger("click");
expect(wrapper.emitted("click")).toHaveLength(1);
});
});
See testing.md for more patterns including Pinia testing and async components.
Step 5: Create Storybook Story
Use CSF3 format for Storybook 7+:
import type { Meta, StoryObj } from "@storybook/vue3";
import ComponentName from "./ComponentName.vue";
const meta: Meta<typeof ComponentName> = {
title: "Components/ComponentName",
component: ComponentName,
tags: ["autodocs"],
argTypes: {
variant: { control: "select", options: ["primary", "secondary"] },
},
};
export default meta;
type Story = StoryObj<typeof meta>;
export const Primary: Story = {
args: { label: "Primary Button", variant: "primary" },
};
See storybook.md for slot stories, decorators, and interactions.
Step 6: Create Barrel Export
index.ts:
export { default as ComponentName } from "./ComponentName.vue";
Common Patterns
v-model support (Vue 3.4+):
<script setup lang="ts">
const modelValue = defineModel<string>({ default: "" });
</script>
Expose methods:
<script setup lang="ts">
const focus = () => inputRef.value?.focus();
defineExpose({ focus });
</script>
Provide/Inject:
// Parent
provide("state", reactive({ active: 0 }));
// Child
const state = inject<{ active: number }>("state");
See advanced-patterns.md for compound components, generics, and Nuxt patterns.
Validation
Before completing:
- Component renders without errors
- TypeScript has no errors
- Props interface uses defineProps with types
- Emits are properly typed
- Tests pass
- Story renders in Storybook
Error Handling
- Module not found: Check import paths and file extensions (
.vue). - CSS module not applying: Ensure using
$stylein template and<style module>. - Test setup missing: Install
@vue/test-utilsand configure Vitest for Vue. - Storybook not rendering: Check
.storybook/main.jsuses@storybook/vue3. - Pinia not available in tests: Call
setActivePinia(createPinia())in beforeEach. - Unsure about conventions: Check existing components in project for patterns.
Resources
Examples
- Component Templates — Full component code examples
- Testing — Vitest patterns and Pinia testing
- Storybook — Story formats and interactions
- Advanced Patterns — Generics, Suspense, Nuxt
More from wesleysmits/agent-skills
writing-product-descriptions
Creates compelling product copy for e-commerce listings. Use when the user asks about product descriptions, e-commerce copy, product pages, marketplace listings, or converting features to benefits.
20writing-long-form-content
Generates comprehensive blog post drafts with proper structure. Use when the user asks to write a full article, create blog content, draft long-form posts, or needs complete written content with SEO optimization.
16writing-youtube-video-scripts
Creates structured video scripts with hooks, segments, and CTAs. Use when the user asks about YouTube scripts, video content, video outlines, talking points, or video intros.
15generating-ebooks-and-lead-magnets
Creates comprehensive ebooks, guides, and downloadable lead magnets with chapter structure and promotional assets. Use when the user asks about ebooks, lead magnets, downloadable guides, gated content, or PDF resources.
11writing-press-releases
Generates professional press releases with headline, dateline, inverted pyramid structure, and boilerplate. Use when the user asks about press releases, media announcements, news releases, PR distribution, or journalist outreach.
11profiling-performance
Runs performance audits and suggests optimizations using Lighthouse and Web Vitals. Use when the user asks about performance, page speed, Core Web Vitals, Lighthouse scores, or wants to optimize rendering and execution.
9