shadcn-vue
This skill provides best practices for using Shadcn Vue components in the fitness app. Use when working with UI components, forms, dialogs, or implementing component patterns.
SKILL.md
| Name | shadcn-vue |
| Description | This skill provides best practices for using Shadcn Vue components in the fitness app. Use when working with UI components, forms, dialogs, or implementing component patterns. |
name: shadcn-vue description: This skill provides best practices for using Shadcn Vue components in the fitness app. Use when working with UI components, forms, dialogs, or implementing component patterns.
Shadcn Vue Best Practices
This skill provides guidance for using Shadcn Vue components effectively in the fitness application.
Core Principles
Component Naming: All Shadcn Vue components are prefixed with UI (e.g., UIButton, UIDialog, UICard, UIInput). This is enforced across the entire codebase for consistency.
Semantic Colors: Use CSS variables for theming instead of arbitrary Tailwind colors:
bg-background,text-foreground- Base colorsbg-primary,text-primary-foreground- Primary actionsbg-secondary,text-secondary-foreground- Secondary elementsbg-muted,text-muted-foreground- Subtle backgroundsbg-accent,text-accent-foreground- Highlightsbg-destructive,text-destructive-foreground- Errors/delete actionsbg-card,text-card-foreground- Card backgroundsborder-border,ring-ring- Borders and focus rings
Documentation: When looking up shadcn components, use the pattern: https://www.shadcn-vue.com/docs/components/{component}.html where {component} is the component name (e.g., tooltip, button, dialog).
UIDialog Pattern (Critical)
NEVER use refs to manage dialog state. Use the v-slot="{ close }" pattern:
<UIDialog v-slot="{ close }">
<UIDialogTrigger as-child>
<UIButton>Open Dialog</UIButton>
</UIDialogTrigger>
<UIDialogContent>
<UIDialogHeader>
<UIDialogTitle>Dialog Title</UIDialogTitle>
<UIDialogDescription>Description text</UIDialogDescription>
</UIDialogHeader>
<!-- Content -->
<UIDialogFooter>
<UIButton variant="outline" @click="close">Cancel</UIButton>
<UIButton @click="handleSubmit(); close()">Save</UIButton>
</UIDialogFooter>
</UIDialogContent>
</UIDialog>
For detailed dialog patterns including multiple dialogs and form integration, see references/dialog-pattern.md.
Form Validation (Required)
All forms MUST use vee-validate with Zod schemas. Never create forms without schema validation.
Basic pattern:
<script setup lang="ts">
import { toTypedSchema } from '@vee-validate/zod'
import { z } from 'zod'
import { useForm } from 'vee-validate'
const formSchema = toTypedSchema(z.object({
name: z.string().min(2).max(50),
email: z.email(),
}))
const { handleSubmit } = useForm({ validationSchema: formSchema })
const onSubmit = handleSubmit((values) => {
// Handle form submission
})
</script>
<template>
<form @submit="onSubmit">
<UIFormField v-slot="{ componentField }" name="name">
<UIFormItem>
<UIFormLabel>Name</UIFormLabel>
<UIFormControl>
<UIInput type="text" v-bind="componentField" />
</UIFormControl>
<UIFormMessage />
</UIFormItem>
</UIFormField>
<UIButton type="submit">Submit</UIButton>
</form>
</template>
For complete form patterns and advanced validation, see references/form-validation.md.
Component Organization
Components follow a folder-based structure:
components/
├── {Feature}/
│ ├── Form/
│ │ ├── Create.vue # Creation form
│ │ ├── Edit.vue # Edit form
│ │ └── Delete.vue # Delete confirmation
│ ├── Card.vue # Display card
│ └── List.vue # List view
Auto-import naming:
components/Goal/Form/Create.vue→<GoalFormCreate />components/Goal/Card.vue→<GoalCard />
For complete component conventions, see references/component-patterns.md.
Common Components Quick Reference
UIButton:
<UIButton variant="default">Submit</UIButton>
<UIButton variant="outline" size="sm">Cancel</UIButton>
<UIButton icon="i-lucide-plus" to="/create">Create</UIButton>
<UIButton variant="destructive" icon="i-lucide-trash">Delete</UIButton>
Variants: default, destructive, outline, secondary, ghost, link
UICard:
<UICard>
<UICardHeader>
<UICardTitle>Title</UICardTitle>
<UICardDescription>Description</UICardDescription>
</UICardHeader>
<UICardContent>Content</UICardContent>
<UICardFooter>
<UIButton>Action</UIButton>
</UICardFooter>
</UICard>
UISelect (multi-component pattern):
<UISelect v-model="value">
<UISelectTrigger>
<UISelectValue placeholder="Select..." />
</UISelectTrigger>
<UISelectContent>
<UISelectGroup>
<UISelectLabel>Group Label</UISelectLabel>
<UISelectItem value="option1">Option 1</UISelectItem>
<UISelectItem value="option2">Option 2</UISelectItem>
</UISelectGroup>
</UISelectContent>
</UISelect>
UIToast (vue-sonner):
import { toast } from 'vue-sonner'
toast.success('Success!', {
description: 'Your changes have been saved.',
})
toast.error('Error!', {
description: 'Something went wrong.',
})
Critical Rules
✅ MUST DO
- Use
UIprefix for all Shadcn components - Use semantic color variables (e.g.,
bg-primary,text-foreground) - Use vee-validate with Zod for all forms
- Use
v-slot="{ close }"pattern for dialogs - Use
UIAlertDialogfor confirmations (never nativeconfirm()) - Ensure keyboard accessibility and screen reader support
- Provide meaningful
aria-labelfor icon-only buttons - Use mobile-first responsive design
❌ NEVER DO
- Mix Shadcn with other component libraries (e.g., Nuxt UI)
- Use arbitrary Tailwind colors (e.g.,
bg-blue-500) - Create forms without Zod validation schemas
- Use refs to manage dialog state (
isOpen.value) - Use native browser dialogs (
confirm(),alert(),prompt()) - Skip loading, error, or empty states in async components
- Rely solely on color to convey information (use icons/text too)
- Use generic button text like "Click here"
Accessibility Requirements
- Keyboard Navigation: All interactive elements must be keyboard accessible
- Screen Reader Support: Provide proper ARIA labels and descriptions
- Color Contrast: Ensure sufficient contrast for text and interactive elements
- Focus Indicators: Never remove focus rings without providing alternatives
- Icon-Only Buttons: Always include
aria-labelattributes - Form Validation: Error messages must be associated with form fields
Reference Files
For detailed information, reference these files as needed:
references/component-patterns.md- Complete component organization and naming conventionsreferences/dialog-pattern.md- Detailed dialog patterns including multiple dialogsreferences/form-validation.md- Complete form validation patterns and examples
Component Documentation URL Pattern
To look up Shadcn Vue component documentation:
https://www.shadcn-vue.com/docs/components/{component}.html
Examples:
- Button:
https://www.shadcn-vue.com/docs/components/button.html - Dialog:
https://www.shadcn-vue.com/docs/components/dialog.html - Form:
https://www.shadcn-vue.com/docs/components/form.html - Select:
https://www.shadcn-vue.com/docs/components/select.html