Audit of existing Vue components in the project. Use when reviewing Vue design system consistency, identifying duplicate patterns, evaluating legacy components (Options API), or before implementing something new.
Scanned 9/9/2026
Install to Claude Code
npx -y skills add pwdev-solucoes/pwdev-claude-marketplace --skill component-audit --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Component Audit?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/pwdev-solucoes-component-audit)More formats (shields.io, HTML) on the badges page.
---
name: component-audit
description: >
Audit of existing Vue components in the project. Use when reviewing Vue design
system consistency, identifying duplicate patterns, evaluating legacy components
(Options API), or before implementing something new.
---
# Skill: Component Audit — Vue 3
## Audit protocol
### 1. Inventory
```bash
# All SFCs
find components/ src/components/ -name "*.vue" | grep -v node_modules | sort
# Installed shadcn-vue components
ls components/ui/ 2>/dev/null || ls src/components/ui/ 2>/dev/null
# Composables
find composables/ src/composables/ -name "*.ts" 2>/dev/null | sort
```
### 2. Identify problematic patterns
```bash
# Legacy Options API (migration candidates)
grep -rl "export default {" components/ --include="*.vue" 2>/dev/null
# Without script setup
grep -rL "script setup" components/ --include="*.vue" 2>/dev/null | grep -v ui/
# Without TypeScript
grep -rl "script setup>" components/ --include="*.vue" 2>/dev/null | \
grep -v "lang=\"ts\""
# Hardcoded hex (outside of tokens)
grep -rn "#[0-9A-Fa-f]\{6\}" components/ --include="*.vue" 2>/dev/null | \
grep -v "ui/"
# Inline styles (outside of dynamic binding)
grep -rn "style=\"" components/ --include="*.vue" 2>/dev/null | grep -v "ui/"
# any in TypeScript
grep -rn ": any" components/ --include="*.vue" 2>/dev/null | grep -v "ui/"
```
### 3. Quality checklist per SFC
**Vue 3 Structure**
- [ ] `<script setup lang="ts">` — no Options API
- [ ] Props with typed `defineProps<Interface>()`
- [ ] Emits with typed `defineEmits<{ event: [type] }>()`
- [ ] Accepts `:class` prop for extensibility
- [ ] Uses `cn()` for conditional class composition
**Design System**
- [ ] Uses CSS tokens (no hardcoded hex)
- [ ] Spacing on 4px scale
- [ ] Variants consistent with shadcn-vue
- [ ] Dark mode functional
**States**
- [ ] Loading state with `<Skeleton>` of same dimensions
- [ ] Empty state with `<Empty>` when list/data can be empty
- [ ] Error state with `<Alert variant="destructive">`
- [ ] Success feedback via `toast()` (vue-sonner)
- [ ] Disabled state with `opacity-50 cursor-not-allowed pointer-events-none`
**Minimum accessibility**
- [ ] Correct semantic element or explicit `role`
- [ ] Accessible label for elements without visible text
- [ ] `focus-visible:ring` present and not removed
### 4. Output → `.planning/ui/component-log.md`
```markdown
## Component Audit — [date]
### Inventory
| Component | File | shadcn-vue base | Issues |
|---|---|---|---|
| UserCard | components/user/UserCard.vue | Card | No Skeleton, Options API |
### Legacy components (Options API)
[list for gradual migration]
### Duplicate patterns
- Pattern "Header with avatar + title" in 4 files → extract component
### Hardcoded tokens found
- UserCard.vue:45 — `color: #6B7280` → use `text-muted-foreground`
### Missing states
- UserList.vue — no `<Empty>` state
- OrderCard.vue — no loading skeleton
### Recommendations
1. [specific and actionable]
```
## Problematic patterns in Vue + shadcn-vue
### Options API → Composition API
```vue
<!-- ❌ Legacy Options API -->
<script>
export default {
data() { return { count: 0 } },
methods: { increment() { this.count++ } }
}
</script>
<!-- ✅ Composition API with script setup -->
<script setup lang="ts">
import { ref } from 'vue'
const count = ref(0)
const increment = () => count.value++
</script>
```
### Conditional classes without cn()
```vue
<!-- ❌ Template literal — does not merge Tailwind correctly -->
<div :class="`base-class ${isActive ? 'active' : ''}`" />
<!-- ✅ cn() with tailwind-merge -->
<div :class="cn('base-class', isActive && 'bg-primary text-primary-foreground')" />
```
### Missing `:class` prop
```vue
<!-- ❌ Not extensible -->
<div class="flex gap-4">
<!-- ✅ Always accept external class -->
<script setup lang="ts">
const props = defineProps<{ class?: string }>()
</script>
<template>
<div :class="cn('flex gap-4', props.class)">
</template>
```
### Skeleton with wrong dimensions
```vue
<!-- ❌ Generic skeleton — causes layout shift -->
<Skeleton class="h-4 w-full" /> <!-- but the content is h-32 -->
<!-- ✅ Skeleton mirrors the actual content -->
<Card v-if="isLoading">
<CardHeader>
<Skeleton class="h-5 w-3/4" />
<Skeleton class="h-4 w-1/2 mt-2" />
</CardHeader>
<CardContent>
<Skeleton class="h-32 w-full" />
</CardContent>
</Card>
```
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!