بنقرة واحدة
forms
Use when building forms - covers React Hook Form, Zod validation, and form patterns
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Use when building forms - covers React Hook Form, Zod validation, and form patterns
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
How to reuse ANY integration check's results in a feature via the universal CheckResultsService (apps/api integration-platform). Use whenever a feature needs data produced by an integration check — "show 2FA status on People", "surface AWS S3 findings in X", "reuse a check's results", "per-user/per-resource results from a connected integration", "which integrations feed task T". Read this BEFORE writing your own IntegrationCheckResult / CheckRunRepository query — don't hand-roll it.
MANDATORY for any UI work in apps/app, apps/portal, or packages/design-system — every component, page, or layout change must work on mobile (~375px), tablet (~768px), desktop (~1280px), and large desktop (~1920px) BY DEFAULT, without being asked. Read this before writing or editing any JSX/TSX that renders visible UI. Triggers on: new component, page, layout, table, toolbar, form, modal/sheet, dashboard, "build UI", "add a column", "add a filter", any styling change.
Use when building or editing frontend UI components, layouts, styling, design system usage, colors, dark mode, or icons.
The contract every new or modified API endpoint must follow so it is correct for the public OpenAPI spec, the MCP server (npm @trycompai/mcp-server), the ValidationPipe, and the docs. Triggers on "new endpoint", "add API", "new DTO", "@Body", "@RequirePermission", "MCP tool", "edit controller in apps/api", "OpenAPI", or whenever editing controllers under apps/api/src/.
Use when SDK generation failed or seeing errors. Triggers on "generation failed", "speakeasy run failed", "SDK build error", "workflow failed", "Step Failed", "why did generation fail"
Use when generating an MCP server from an OpenAPI spec with Speakeasy. Triggers on "generate MCP server", "MCP server", "Model Context Protocol", "AI assistant tools", "Claude tools", "speakeasy MCP", "mcp-typescript"
| name | forms |
| description | Use when building forms - covers React Hook Form, Zod validation, and form patterns |
Source Cursor rule: .cursor/rules/forms.mdc.
Original Cursor alwaysApply: false.
All forms MUST use React Hook Form with Zod validation.
import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import { Button, Input } from '@trycompai/design-system';
// 1. Define schema
const formSchema = z.object({
email: z.string().email('Invalid email'),
password: z.string().min(8, 'Min 8 characters'),
});
// 2. Infer type
type FormData = z.infer<typeof formSchema>;
// 3. Use in component
function MyForm() {
const {
register,
handleSubmit,
formState: { errors, isSubmitting },
} = useForm<FormData>({
resolver: zodResolver(formSchema),
});
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Input {...register('email')} />
{errors.email && <p>{errors.email.message}</p>}
<Button type="submit" loading={isSubmitting}>
Submit
</Button>
</form>
);
}
const profileSchema = z.object({
// Strings
name: z.string().min(1, 'Required'),
email: z.string().email(),
website: z.string().url().optional(),
// Numbers (coerce for inputs)
age: z.coerce.number().int().min(0),
price: z.coerce.number().positive(),
// Arrays
tags: z.array(z.string()).min(1),
// Enums
status: z.enum(['active', 'inactive']),
});
// Cross-field validation
const passwordSchema = z.object({
password: z.string().min(8),
confirmPassword: z.string(),
}).refine(d => d.password === d.confirmPassword, {
message: "Passwords don't match",
path: ['confirmPassword'],
});
import { Controller } from 'react-hook-form';
import { Select, SelectContent, SelectItem, SelectTrigger } from '@trycompai/design-system';
<Controller
name="status"
control={control}
render={({ field }) => (
<Select onValueChange={field.onChange} value={field.value}>
<SelectTrigger>{field.value || 'Select...'}</SelectTrigger>
<SelectContent>
<SelectItem value="active">Active</SelectItem>
<SelectItem value="inactive">Inactive</SelectItem>
</SelectContent>
</Select>
)}
/>
const {
register,
handleSubmit,
control,
watch, // Watch field values
setValue, // Set field programmatically
reset, // Reset form
setError, // Set error manually
formState: {
errors, // Field errors
isSubmitting, // Submitting
isValid, // All valid
isDirty, // Modified
},
} = useForm<FormData>({
resolver: zodResolver(schema),
mode: 'onChange', // Validate on change
});
const onSubmit = async (data: FormData) => {
try {
await submitToApi(data);
} catch (error) {
// Field-specific error
setError('email', { message: 'Email taken' });
// Or root error
setError('root', { message: 'Something went wrong' });
}
};
// Display root error
{errors.root && <p>{errors.root.message}</p>}
import { useFieldArray } from 'react-hook-form';
const { fields, append, remove } = useFieldArray({
control,
name: 'items',
});
{fields.map((field, index) => (
<div key={field.id}>
<Input {...register(`items.${index}.name`)} />
<Button type="button" onClick={() => remove(index)}>Remove</Button>
</div>
))}
<Button type="button" onClick={() => append({ name: '' })}>Add</Button>
// ❌ useState for form fields
const [email, setEmail] = useState('');
// ❌ Manual validation
if (email.length < 5) setError('Too short');
// ❌ Missing button type (defaults to submit)
<Button onClick={handleCancel}>Cancel</Button>
// ✅ Correct
const { register } = useForm();
const schema = z.object({ email: z.string().min(5) });
<Button type="button" onClick={handleCancel}>Cancel</Button>