Skip to content

Commit ccaabc5

Browse files
Improve formatting and structure of LLM documentation
- Add better section headers and explanations for component usage - Improve DatePicker, DropdownMenuSelect, and OTPInput sections with consistent formatting - Enhance Advanced Form Patterns with clearer explanations and use cases - Add missing imports and better structure to Success Handling section - Improve Checkbox Groups section with step-by-step implementation - Enhance Key Implementation Notes with code examples and visual formatting - Add essential patterns and important reminders for LLM implementation
1 parent 9a8c9bb commit ccaabc5

1 file changed

Lines changed: 145 additions & 39 deletions

File tree

llms.txt

Lines changed: 145 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -208,10 +208,13 @@ const sizeOptions = [
208208
label="Birth Date"
209209
description="Select your date of birth"
210210
className="custom-class"
211+
disabled={isSubmitting} // Optional: disable during form submission
211212
/>
213+
```
212214

213-
// Zod schema for date fields
214-
const schema = z.object({
215+
**Zod Schema for Date Fields:**
216+
```typescript
217+
const formSchema = z.object({
215218
birthDate: z.coerce.date({
216219
required_error: 'Please select a date',
217220
}),
@@ -224,14 +227,17 @@ const schema = z.object({
224227
name="fruit"
225228
label="Select Fruit"
226229
description="Choose your favorite fruit"
230+
disabled={isSubmitting} // Optional: disable during form submission
227231
>
228232
<DropdownMenuSelectItem value="apple">Apple</DropdownMenuSelectItem>
229233
<DropdownMenuSelectItem value="banana">Banana</DropdownMenuSelectItem>
230234
<DropdownMenuSelectItem value="orange">Orange</DropdownMenuSelectItem>
231235
</DropdownMenuSelect>
236+
```
232237

233-
// Zod schema for select fields
234-
const schema = z.object({
238+
**Zod Schema for Select Fields:**
239+
```typescript
240+
const formSchema = z.object({
235241
fruit: z.string({
236242
required_error: 'Please select a fruit',
237243
}),
@@ -246,10 +252,13 @@ const schema = z.object({
246252
description="Enter the 6-digit code sent to your phone"
247253
maxLength={6} // Required: number of digits
248254
className="custom-class"
255+
disabled={isSubmitting} // Optional: disable during form submission
249256
/>
257+
```
250258

251-
// Zod schema for OTP
252-
const schema = z.object({
259+
**Zod Schema for OTP Fields:**
260+
```typescript
261+
const formSchema = z.object({
253262
otp: z.string().min(6, 'OTP must be 6 digits'),
254263
});
255264
```
@@ -302,7 +311,12 @@ const CustomMessage = (props: React.ComponentPropsWithoutRef<typeof FormMessage>
302311
## Advanced Form Patterns
303312

304313
### Custom Submit Handlers
305-
Use `submitHandlers.onValid` to transform data before submission:
314+
315+
Use `submitHandlers.onValid` to transform data before submission. This is useful for:
316+
- Adding computed fields (timestamps, IDs)
317+
- Transforming data formats
318+
- Combining multiple fields
319+
- Adding metadata
306320

307321
```typescript
308322
const methods = useRemixForm<FormData>({
@@ -319,6 +333,7 @@ const methods = useRemixForm<FormData>({
319333
...data,
320334
timestamp: new Date().toISOString(),
321335
processed: true,
336+
fullName: `${data.firstName} ${data.lastName}`, // Combine fields
322337
};
323338

324339
fetcher.submit(
@@ -334,20 +349,34 @@ const methods = useRemixForm<FormData>({
334349
```
335350

336351
### Checkbox Groups with Custom Submission
352+
353+
When working with multiple checkboxes, you often want to transform the boolean object into an array of selected values:
354+
355+
**Schema for Checkbox Group:**
337356
```typescript
338-
// Schema for checkbox group
339357
const formSchema = z.object({
340358
colors: z.object({
341359
red: z.boolean().default(false),
342360
blue: z.boolean().default(false),
343361
green: z.boolean().default(false),
344362
}),
345363
});
364+
```
365+
366+
**Form Implementation:**
367+
```typescript
368+
<div className="space-y-2">
369+
<Checkbox name="colors.red" label="Red" />
370+
<Checkbox name="colors.blue" label="Blue" />
371+
<Checkbox name="colors.green" label="Green" />
372+
</div>
373+
```
346374

347-
// Custom submission to transform checkbox data
375+
**Custom Submission Handler:**
376+
```typescript
348377
submitHandlers: {
349378
onValid: (data) => {
350-
// Extract selected colors
379+
// Extract selected colors into array
351380
const selectedColors = Object.entries(data.colors)
352381
.filter(([_, selected]) => selected)
353382
.map(([color]) => color);
@@ -513,25 +542,50 @@ export const action = async ({ request }: ActionFunctionArgs) => {
513542
## Success Handling & Redirects
514543

515544
### Success Messages
545+
546+
Display success messages from server responses:
547+
516548
```typescript
517549
// In your component
518550
{fetcher.data?.message && (
519551
<div className="mt-4 p-4 bg-green-50 border border-green-200 rounded-md">
520552
<p className="text-green-700 font-medium">{fetcher.data.message}</p>
521553
</div>
522554
)}
555+
556+
// Error messages
557+
{fetcher.data?.errors?._form && (
558+
<div className="mt-4 p-4 bg-red-50 border border-red-200 rounded-md">
559+
<p className="text-red-700 font-medium">{fetcher.data.errors._form.message}</p>
560+
</div>
561+
)}
523562
```
524563

525564
### Programmatic Redirects
565+
566+
**Client-side redirect handling:**
526567
```typescript
527-
// In your component - handle redirect from server response
528-
useEffect(() => {
529-
if (fetcher.data?.redirectTo) {
530-
navigate(fetcher.data.redirectTo);
531-
}
532-
}, [fetcher.data?.redirectTo, navigate]);
568+
import { useNavigate } from 'react-router';
569+
570+
const MyForm = () => {
571+
const navigate = useNavigate();
572+
const fetcher = useFetcher();
573+
574+
// Handle redirect from server response
575+
useEffect(() => {
576+
if (fetcher.data?.redirectTo) {
577+
navigate(fetcher.data.redirectTo);
578+
}
579+
}, [fetcher.data?.redirectTo, navigate]);
580+
581+
// ... rest of component
582+
};
583+
```
584+
585+
**Server-side redirect:**
586+
```typescript
587+
import { redirect } from 'react-router';
533588

534-
// Or use Remix's redirect in the action
535589
export const action = async ({ request }: ActionFunctionArgs) => {
536590
// ... validation and processing
537591

@@ -541,7 +595,12 @@ export const action = async ({ request }: ActionFunctionArgs) => {
541595
```
542596

543597
### Optimistic UI Updates
598+
599+
Show immediate feedback while form is submitting:
600+
544601
```typescript
602+
import { useState, useEffect } from 'react';
603+
545604
const MyForm = () => {
546605
const fetcher = useFetcher();
547606
const [optimisticMessage, setOptimisticMessage] = useState('');
@@ -876,29 +935,76 @@ export const action = async ({ request }: ActionFunctionArgs) => {
876935
export default ComprehensiveForm;
877936
```
878937

879-
This example demonstrates:
880-
- All major form components (TextField, Textarea, Checkbox, RadioGroup, DatePicker, DropdownMenuSelect)
881-
- Complex validation with Zod schemas
882-
- Conditional field display based on form values
883-
- Custom submit handlers with data transformation
884-
- Loading states and disabled inputs during submission
885-
- Error handling for both client and server-side validation
886-
- Success messages and redirect handling
887-
- Responsive layout with proper spacing and styling
888-
- Accessibility features built-in to all components
938+
**This example demonstrates:**
939+
- All major form components (TextField, Textarea, Checkbox, RadioGroup, DatePicker, DropdownMenuSelect)
940+
- Complex validation with Zod schemas
941+
- Conditional field display based on form values
942+
- Custom submit handlers with data transformation
943+
- Loading states and disabled inputs during submission
944+
- Error handling for both client and server-side validation
945+
- Success messages and redirect handling
946+
- Responsive layout with proper spacing and styling
947+
- Accessibility features built-in to all components
889948

890-
This comprehensive example should serve as a complete reference for implementing any form using the LambdaCurry Forms library!
949+
This comprehensive example serves as a complete reference for implementing any form using the LambdaCurry Forms library!
891950

892-
## Key Implementation Notes for LLMs
951+
---
893952

894-
1. **Always use RemixFormProvider**: Wrap your form with `<RemixFormProvider {...methods}>` to provide form context
895-
2. **Form submission**: Use `fetcher.Form` with `onSubmit={methods.handleSubmit}` for proper form handling
896-
3. **Error handling**: Errors are automatically displayed via the `FormMessage` component when validation fails
897-
4. **Loading states**: Use `fetcher.state === 'submitting'` to show loading states and disable inputs
898-
5. **Custom components**: Override any part of the form structure using the `components` prop
899-
6. **Conditional rendering**: Use `methods.watch()` to conditionally show/hide fields based on form values
900-
7. **Data transformation**: Use `submitHandlers.onValid` to transform data before submission
901-
8. **Server validation**: Use `getValidatedFormData` in your action to validate and handle form data
902-
9. **Success handling**: Display success messages and handle redirects from the server response
903-
10. **Accessibility**: All components include proper ARIA attributes and accessibility features by default
953+
## Key Implementation Notes for LLMs
904954

955+
### Essential Patterns to Follow:
956+
957+
1. **Form Provider Setup**
958+
```typescript
959+
<RemixFormProvider {...methods}>
960+
<fetcher.Form onSubmit={methods.handleSubmit}>
961+
{/* Form components */}
962+
</fetcher.Form>
963+
</RemixFormProvider>
964+
```
965+
966+
2. **Error Handling**
967+
- Errors display automatically via `FormMessage` component
968+
- Server errors: `return { errors }` from action
969+
- Field-specific: `errors.fieldName.message`
970+
- Form-level: `errors._form.message`
971+
972+
3. **Loading States**
973+
```typescript
974+
const isSubmitting = fetcher.state === 'submitting';
975+
<TextField disabled={isSubmitting} />
976+
<Button disabled={isSubmitting}>
977+
{isSubmitting ? 'Submitting...' : 'Submit'}
978+
</Button>
979+
```
980+
981+
4. **Conditional Fields**
982+
```typescript
983+
const watchValue = methods.watch('fieldName');
984+
{watchValue === 'condition' && <TextField name="conditionalField" />}
985+
```
986+
987+
5. **Data Transformation**
988+
```typescript
989+
submitHandlers: {
990+
onValid: (data) => {
991+
const transformed = { ...data, computed: 'value' };
992+
fetcher.submit(createFormData(transformed), { method: 'post' });
993+
}
994+
}
995+
```
996+
997+
6. **Server Validation**
998+
```typescript
999+
export const action = async ({ request }) => {
1000+
const { data, errors } = await getValidatedFormData(request, zodResolver(schema));
1001+
if (errors) return { errors };
1002+
// Process data...
1003+
};
1004+
```
1005+
1006+
### Important Reminders:
1007+
- 🔥 **Always import from `@lambdacurry/forms/remix-hook-form/`** for form-aware components
1008+
- 🔥 **Use `createFormData()` for custom submissions** to ensure proper formatting
1009+
- 🔥 **All components are accessible by default** - no additional ARIA setup needed
1010+
- 🔥 **Form context is automatic** - no need to pass `control` props manually

0 commit comments

Comments
 (0)