Skip to content

Commit a52c2ba

Browse files
docs: [M3-8932] - Add Form Validation Best Practices (#11298)
* docs: [M3-8932] - Add Form Validation Best Practices * Minor updates * Added changeset: Add Documentation for Form Validation Best Practices * Update docs * generalize --------- Co-authored-by: Jaalah Ramos <[email protected]>
1 parent 4b3fe8a commit a52c2ba

File tree

2 files changed

+76
-0
lines changed

2 files changed

+76
-0
lines changed

docs/development-guide/15-composition.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,74 @@ The Linode Create Page is a good example of a complex form that is built using r
5252
### Uncontrolled Forms
5353
Uncontrolled forms are a type of form that does not have a state for its values. It is often used for simple forms that do not need to be controlled, such as forms with a single input field or call to action.
5454

55+
## Form Validation (React Hook Form)
56+
### Best Practices
57+
1. Keep API validation in `@linode/validation` package
58+
2. Create extended schemas in `@linode/manager` package when you need validation beyond the API contract
59+
3. Use yup.concat() to extend existing schemas
60+
4. Add custom validation logic within the resolver function
61+
5. Include type definitions for form values and context
62+
63+
### Simple Schema Extension
64+
For basic form validation, extend the API schema directly:
65+
66+
```typescript
67+
import { CreateWidgetSchema } from '@linode/validation';
68+
import { object, string } from 'yup';
69+
import { yupResolver } from '@hookform/resolvers/yup';
70+
71+
const extendedSchema = CreateWidgetSchema.concat(
72+
object({
73+
customField: string().required('Required field'),
74+
})
75+
);
76+
77+
const form = useForm({
78+
resolver: yupResolver(extendedSchema)
79+
});
80+
```
81+
82+
### Complex Schema Extensions
83+
You may create a `resolver` function that handles the validation (see: [ManageImageRegionsForm.tsx](https://github.com/linode/manager/blob/develop/packages/manager/src/features/Images/ImagesLanding/ImageRegions/ManageImageRegionsForm.tsx#L189-L213)):
84+
85+
```typescript
86+
// Step 1: Create a Resolver Function
87+
// This function validates your form data against specific requirements
88+
89+
type Resolver<FormData, Context> = (values: FormData, context: Context) => {
90+
errors: Record<string, any>;
91+
values: FormData;
92+
};
93+
94+
// Example resolver that checks if at least one item from a list is selected
95+
const resolver: Resolver<YourFormData, YourContext> = (values, context) => {
96+
// Check if at least one valid option is selected
97+
const hasValidSelection = values.selectedItems.some(
98+
item => context.availableItems.includes(item)
99+
);
100+
101+
if (!hasValidSelection) {
102+
return {
103+
errors: {
104+
selectedItems: {
105+
message: 'Please select at least one valid option',
106+
type: 'validate'
107+
}
108+
},
109+
values
110+
};
111+
}
112+
113+
return { errors: {}, values };
114+
};
115+
116+
// Step 2: Use the Resolver in Your Form
117+
const form = useForm({
118+
resolver,
119+
defaultValues: { selectedItems: [] },
120+
context: { availableItems: ['item1', 'item2'] }
121+
});
122+
```
123+
124+
### Additional Complexity
125+
When working with multiple sequential schemas that require validation, you can create a resolver map and function (see: [LinodeCreate/resolvers.ts](https://github.com/linode/manager/blob/develop/packages/manager/src/features/Linodes/LinodeCreate/resolvers.ts])).
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@linode/manager": Tech Stories
3+
---
4+
5+
Add Documentation for Form Validation Best Practices ([#11298](https://github.com/linode/manager/pull/11298))

0 commit comments

Comments
 (0)