Skip to content

Commit 6cfd37a

Browse files
committed
chore: Version bump to 0.18.0
- Bump @lambdacurry/forms package version to 0.18.0 - Updated dependencies from npm version command - Includes FormError component implementation and documentation updates
1 parent 6a1d154 commit 6cfd37a

3 files changed

Lines changed: 5569 additions & 11278 deletions

File tree

llms.txt

Lines changed: 159 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,70 @@ const formSchema = z.object({
107107
type FormData = z.infer<typeof formSchema>;
108108
```
109109

110-
### 3. Form Component Setup
110+
### 3. Complete Login Form Example with FormError
111+
112+
```typescript
113+
const LoginForm = () => {
114+
const fetcher = useFetcher<{
115+
message?: string;
116+
errors?: Record<string, { message: string }>
117+
}>();
118+
119+
const methods = useRemixForm<FormData>({
120+
resolver: zodResolver(formSchema),
121+
defaultValues: {
122+
email: '',
123+
password: '',
124+
},
125+
fetcher,
126+
submitConfig: {
127+
action: '/login',
128+
method: 'post',
129+
},
130+
});
131+
132+
const isSubmitting = fetcher.state === 'submitting';
133+
134+
return (
135+
<RemixFormProvider {...methods}>
136+
<fetcher.Form onSubmit={methods.handleSubmit} className="max-w-md mx-auto p-6 space-y-4">
137+
<h2 className="text-xl font-semibold text-gray-900">Sign In</h2>
138+
139+
{/* Form-level error display */}
140+
<FormError className="mb-4" />
141+
142+
<TextField
143+
name="email"
144+
type="email"
145+
label="Email Address"
146+
placeholder="Enter your email"
147+
disabled={isSubmitting}
148+
/>
149+
150+
<TextField
151+
name="password"
152+
type="password"
153+
label="Password"
154+
placeholder="Enter your password"
155+
disabled={isSubmitting}
156+
/>
157+
158+
<Button type="submit" disabled={isSubmitting} className="w-full">
159+
{isSubmitting ? 'Signing In...' : 'Sign In'}
160+
</Button>
161+
162+
{fetcher.data?.message && (
163+
<div className="mt-4 p-4 bg-green-50 border border-green-200 rounded-md">
164+
<p className="text-green-700 font-medium">{fetcher.data.message}</p>
165+
</div>
166+
)}
167+
</fetcher.Form>
168+
</RemixFormProvider>
169+
);
170+
};
171+
```
172+
173+
### 4. General Form Component Setup
111174
```typescript
112175
const MyFormComponent = () => {
113176
const fetcher = useFetcher<{ message: string; errors?: Record<string, { message: string }> }>();
@@ -143,7 +206,7 @@ const MyFormComponent = () => {
143206
};
144207
```
145208

146-
### 4. Server Action Handler
209+
### 5. Server Action Handler with FormError Support
147210
```typescript
148211
export const action = async ({ request }: ActionFunctionArgs) => {
149212
const { data, errors } = await getValidatedFormData<FormData>(
@@ -155,10 +218,18 @@ export const action = async ({ request }: ActionFunctionArgs) => {
155218
return { errors };
156219
}
157220

158-
// Process the validated data
159-
console.log('Form data:', data);
160-
161-
return { message: 'Form submitted successfully!' };
221+
// Business logic validation
222+
try {
223+
const user = await authenticateUser(data.email, data.password);
224+
return { message: 'Login successful!', redirectTo: '/dashboard' };
225+
} catch (error) {
226+
// Return form-level error using _form key
227+
return {
228+
errors: {
229+
_form: { message: 'Invalid credentials. Please try again.' }
230+
}
231+
};
232+
}
162233
};
163234
```
164235

@@ -1071,8 +1142,90 @@ This comprehensive example serves as a complete reference for implementing any f
10711142
};
10721143
```
10731144

1145+
7. **FormError Placement Options**
1146+
```typescript
1147+
// Top of form (most common)
1148+
<FormError className="mb-4" />
1149+
1150+
// Between sections
1151+
<FormError className="my-4 text-center" />
1152+
1153+
// Bottom of form
1154+
<FormError className="mt-4" />
1155+
1156+
// Multiple placements with different styling
1157+
<FormError className="mb-4 p-3 bg-red-50 rounded" />
1158+
<FormError className="mt-4 text-sm text-red-600" />
1159+
```
1160+
1161+
8. **Custom FormError Styling**
1162+
```typescript
1163+
const CustomErrorMessage = (props: React.ComponentPropsWithoutRef<typeof FormMessage>) => (
1164+
<div className="alert alert-error">
1165+
<AlertIcon />
1166+
<FormMessage {...props} />
1167+
</div>
1168+
);
1169+
1170+
<FormError
1171+
components={{
1172+
FormMessage: CustomErrorMessage,
1173+
}}
1174+
/>
1175+
```
1176+
1177+
9. **Server Action Error Patterns**
1178+
```typescript
1179+
// Field-level error
1180+
return {
1181+
errors: {
1182+
email: { message: 'Email already exists' }
1183+
}
1184+
};
1185+
1186+
// Form-level error
1187+
return {
1188+
errors: {
1189+
_form: { message: 'Server error occurred' }
1190+
}
1191+
};
1192+
1193+
// Multiple error types
1194+
return {
1195+
errors: {
1196+
email: { message: 'Email already exists' },
1197+
_form: { message: 'Please fix the errors above' }
1198+
}
1199+
};
1200+
```
1201+
1202+
## FormError Best Practices
1203+
1204+
### 1. Error Key Conventions
1205+
- Use `_form` for general form-level errors
1206+
- Use descriptive keys for specific categories (`payment`, `shipping`, `auth`)
1207+
- Be consistent across your application
1208+
1209+
### 2. Error Message Guidelines
1210+
- **Be specific**: "Server temporarily unavailable" vs "Error occurred"
1211+
- **Be actionable**: "Please try again in a few minutes" vs "Failed"
1212+
- **Be user-friendly**: Avoid technical jargon and error codes
1213+
1214+
### 3. Placement Strategy
1215+
- **Top placement**: For critical errors that should be seen immediately
1216+
- **Inline placement**: For contextual errors related to specific sections
1217+
- **Bottom placement**: For summary or less critical errors
1218+
1219+
### 4. Component Integration
1220+
- FormError works seamlessly with all existing form components
1221+
- Maintains the same component override pattern as other form components
1222+
- Automatically integrates with form context and validation state
1223+
10741224
### Important Reminders:
10751225
- 🔥 **Always import from `@lambdacurry/forms`** for form-aware components
10761226
- 🔥 **Use `createFormData()` for custom submissions** to ensure proper formatting
10771227
- 🔥 **All components are accessible by default** - no additional ARIA setup needed
10781228
- 🔥 **Form context is automatic** - no need to pass `control` props manually
1229+
- 🔥 **FormError provides form-level error handling** - use it for server errors, auth failures, and general business logic errors
1230+
1231+
This comprehensive guide provides everything needed to implement forms with both field-level and form-level error handling using the LambdaCurry Forms library!

packages/components/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@lambdacurry/forms",
3-
"version": "0.17.3",
3+
"version": "0.18.0",
44
"type": "module",
55
"main": "./dist/index.js",
66
"types": "./dist/index.d.ts",

0 commit comments

Comments
 (0)