Add form implementation standards for Shadcn/UI components with vee-validate
- Introduce critical guidelines for using Shadcn/UI form components in conjunction with vee-validate for form handling. - Provide detailed examples for required form setup, template structure, and key requirements to ensure proper validation and accessibility. - Emphasize the importance of type safety using Zod schema for validation and correct form handling practices. These updates aim to standardize form implementations across the application, enhancing consistency and maintainability.
This commit is contained in:
parent
b0a2d1a6df
commit
3679c719a3
1 changed files with 148 additions and 0 deletions
148
CLAUDE.md
148
CLAUDE.md
|
|
@ -186,6 +186,153 @@ export const myModule: ModulePlugin = {
|
|||
- Module configs in `src/app.config.ts`
|
||||
- Centralized config parsing and validation
|
||||
|
||||
### **Form Implementation Standards**
|
||||
|
||||
**CRITICAL: Always use Shadcn/UI Form Components with vee-validate**
|
||||
|
||||
All forms in the application MUST follow the official Shadcn Vue form implementation pattern:
|
||||
|
||||
**Required Form Setup:**
|
||||
```typescript
|
||||
import { useForm } from 'vee-validate'
|
||||
import { toTypedSchema } from '@vee-validate/zod'
|
||||
import * as z from 'zod'
|
||||
import {
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage,
|
||||
} from '@/components/ui/form'
|
||||
|
||||
// 1. Define Zod schema for validation
|
||||
const formSchema = toTypedSchema(z.object({
|
||||
name: z.string().min(1, "Name is required").max(100, "Name too long"),
|
||||
email: z.string().email("Invalid email address").optional(),
|
||||
items: z.array(z.string()).min(1, "Select at least one item"),
|
||||
}))
|
||||
|
||||
// 2. Set up form with vee-validate
|
||||
const form = useForm({
|
||||
validationSchema: formSchema,
|
||||
initialValues: {
|
||||
name: '',
|
||||
email: '',
|
||||
items: []
|
||||
}
|
||||
})
|
||||
|
||||
// 3. Destructure form methods
|
||||
const { setFieldValue, resetForm, values, meta } = form
|
||||
|
||||
// 4. Create form validation computed
|
||||
const isFormValid = computed(() => meta.value.valid)
|
||||
|
||||
// 5. Create submit handler with form.handleSubmit
|
||||
const onSubmit = form.handleSubmit(async (values) => {
|
||||
console.log('Form submitted:', values)
|
||||
// Handle form submission logic
|
||||
})
|
||||
```
|
||||
|
||||
**Required Form Template Structure:**
|
||||
```vue
|
||||
<template>
|
||||
<!-- form.handleSubmit automatically prevents default submission -->
|
||||
<form @submit="onSubmit" class="space-y-6">
|
||||
<!-- Text Input Field -->
|
||||
<FormField v-slot="{ componentField }" name="name">
|
||||
<FormItem>
|
||||
<FormLabel>Name *</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder="Enter name"
|
||||
v-bind="componentField"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormDescription>Enter your full name</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<!-- Multiple Checkbox Selection -->
|
||||
<FormField name="items">
|
||||
<FormItem>
|
||||
<div class="mb-4">
|
||||
<FormLabel class="text-base">Items *</FormLabel>
|
||||
<FormDescription>Select one or more items</FormDescription>
|
||||
</div>
|
||||
<div v-for="item in availableItems" :key="item.id">
|
||||
<FormField
|
||||
v-slot="{ value, handleChange }"
|
||||
type="checkbox"
|
||||
:value="item.id"
|
||||
:unchecked-value="false"
|
||||
name="items"
|
||||
>
|
||||
<FormItem class="flex flex-row items-start space-x-3 space-y-0">
|
||||
<FormControl>
|
||||
<Checkbox
|
||||
:model-value="value.includes(item.id)"
|
||||
@update:model-value="handleChange"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormLabel class="font-normal">{{ item.name }}</FormLabel>
|
||||
</FormItem>
|
||||
</FormField>
|
||||
</div>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
</FormField>
|
||||
|
||||
<!-- Submit Button -->
|
||||
<Button
|
||||
type="submit"
|
||||
:disabled="isLoading || !isFormValid"
|
||||
>
|
||||
{{ isLoading ? 'Submitting...' : 'Submit' }}
|
||||
</Button>
|
||||
</form>
|
||||
</template>
|
||||
```
|
||||
|
||||
**Key Form Requirements:**
|
||||
- ✅ **Form validation**: Use `@submit="onSubmit"` - form.handleSubmit automatically prevents page refresh
|
||||
- ✅ **Button state**: Disable submit button with `!isFormValid` until all required fields are valid
|
||||
- ✅ **Error display**: Use `<FormMessage />` for automatic error display
|
||||
- ✅ **Field binding**: Use `v-bind="componentField"` for proper form field integration
|
||||
- ✅ **Checkbox arrays**: Use nested FormField pattern for multiple checkbox selection
|
||||
- ✅ **Type safety**: Zod schema provides full TypeScript type safety
|
||||
|
||||
**❌ NEVER do this:**
|
||||
```vue
|
||||
<!-- Wrong: Manual form handling without vee-validate -->
|
||||
<form @submit.prevent="handleSubmit">
|
||||
|
||||
<!-- Wrong: Direct v-model bypasses form validation -->
|
||||
<Input v-model="myValue" />
|
||||
|
||||
<!-- Wrong: Manual validation instead of using meta.valid -->
|
||||
<Button :disabled="!name || !email">Submit</Button>
|
||||
```
|
||||
|
||||
**✅ ALWAYS do this:**
|
||||
```vue
|
||||
<!-- Correct: Uses form.handleSubmit for proper form handling -->
|
||||
<form @submit="onSubmit">
|
||||
|
||||
<!-- Correct: Uses FormField with componentField binding -->
|
||||
<FormField v-slot="{ componentField }" name="fieldName">
|
||||
<FormControl>
|
||||
<Input v-bind="componentField" />
|
||||
</FormControl>
|
||||
</FormField>
|
||||
|
||||
<!-- Correct: Uses form meta for validation state -->
|
||||
<Button :disabled="!isFormValid">Submit</Button>
|
||||
```
|
||||
|
||||
### **Code Conventions:**
|
||||
- Use TypeScript interfaces over types for extendability
|
||||
- Prefer functional and declarative patterns over classes
|
||||
|
|
@ -195,6 +342,7 @@ export const myModule: ModulePlugin = {
|
|||
- Implement lazy loading for non-critical components
|
||||
- Optimize images using WebP format with lazy loading
|
||||
- **ALWAYS use dependency injection for cross-module service access**
|
||||
- **ALWAYS use Shadcn Form components for all form implementations**
|
||||
|
||||
**Build Configuration:**
|
||||
- Vite config includes PWA, image optimization, and bundle analysis
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue