|
| 1 | +# FormOptionsProvider |
| 2 | + |
| 3 | +> The `FormOptionsProvider` component is part of Conform's future export. These APIs are experimental and may change in minor versions. [Learn more](https://github.com/edmundhung/conform/discussions/954) |
| 4 | +
|
| 5 | +A React component that provides global form options to all forms in your application. |
| 6 | + |
| 7 | +```tsx |
| 8 | +import { FormOptionsProvider } from '@conform-to/react/future'; |
| 9 | + |
| 10 | +export default function App() { |
| 11 | + return ( |
| 12 | + <FormOptionsProvider shouldValidate="onBlur" shouldRevalidate="onInput"> |
| 13 | + {/* Your app components */} |
| 14 | + </FormOptionsProvider> |
| 15 | + ); |
| 16 | +} |
| 17 | +``` |
| 18 | + |
| 19 | +## Props |
| 20 | + |
| 21 | +All props are optional. When a prop is not provided, it inherits the default value or from a parent `FormOptionsProvider` if nested. |
| 22 | + |
| 23 | +### `shouldValidate?: 'onSubmit' | 'onBlur' | 'onInput'` |
| 24 | + |
| 25 | +Determines when validation should run for the first time on a field. Default is `onSubmit`. |
| 26 | + |
| 27 | +This option sets the default validation timing for all forms in your application. Individual forms can override this by passing their own `shouldValidate` option to [useForm](./useForm.md). |
| 28 | + |
| 29 | +```tsx |
| 30 | +<FormOptionsProvider shouldValidate="onBlur"> |
| 31 | + {/* All forms will validate on blur by default */} |
| 32 | +</FormOptionsProvider> |
| 33 | +``` |
| 34 | + |
| 35 | +### `shouldRevalidate?: 'onSubmit' | 'onBlur' | 'onInput'` |
| 36 | + |
| 37 | +Determines when validation should run again after the field has been validated once. Default is the same as `shouldValidate`. |
| 38 | + |
| 39 | +This is useful when you want an immediate update after the user has interacted with a field. For example, validate on blur initially, but revalidate on every input after the first validation. |
| 40 | + |
| 41 | +```tsx |
| 42 | +<FormOptionsProvider shouldValidate="onBlur" shouldRevalidate="onInput"> |
| 43 | + {/* Validate on blur, but show live feedback after first validation */} |
| 44 | +</FormOptionsProvider> |
| 45 | +``` |
| 46 | + |
| 47 | +### `defineCustomMetadata?: <FieldShape, ErrorShape>(metadata: BaseMetadata<FieldShape, ErrorShape>) => CustomMetadata` |
| 48 | + |
| 49 | +A function that defines custom metadata properties for your form fields. This is particularly useful when integrating with UI libraries or custom form components. |
| 50 | + |
| 51 | +```tsx |
| 52 | +import { |
| 53 | + FormOptionsProvider, |
| 54 | + type BaseMetadata, |
| 55 | +} from '@conform-to/react/future'; |
| 56 | +import type { TextField } from './components/TextField'; |
| 57 | + |
| 58 | +// Define custom metadata properties that matches the type of our custom form components |
| 59 | +function defineCustomMetadata<FieldShape, ErrorShape>( |
| 60 | + metadata: BaseMetadata<FieldShape, ErrorShape>, |
| 61 | +) { |
| 62 | + return { |
| 63 | + get textFieldProps() { |
| 64 | + return { |
| 65 | + name: metadata.name, |
| 66 | + defaultValue: metadata.defaultValue, |
| 67 | + isInvalid: !metadata.valid, |
| 68 | + errors: metadata.errors, |
| 69 | + } satisfies Partial<React.ComponentProps<typeof TextField>>; |
| 70 | + }, |
| 71 | + }; |
| 72 | +} |
| 73 | + |
| 74 | +// Extend the CustomMetadata interface with our implementation |
| 75 | +// This makes the custom metadata types available on all field metadata objects |
| 76 | +declare module '@conform-to/react/future' { |
| 77 | + interface CustomMetadata<FieldShape, ErrorShape> |
| 78 | + extends ReturnType<typeof defineCustomMetadata<FieldShape, ErrorShape>> {} |
| 79 | +} |
| 80 | + |
| 81 | +// Wrap your app with FormOptionsProvider |
| 82 | +<FormOptionsProvider defineCustomMetadata={defineCustomMetadata}> |
| 83 | + <App /> |
| 84 | +</FormOptionsProvider>; |
| 85 | +``` |
| 86 | + |
| 87 | +Once defined, custom metadata properties are available on all field metadata objects: |
| 88 | + |
| 89 | +```tsx |
| 90 | +function LoginForm() { |
| 91 | + const { form, fields } = useForm({ |
| 92 | + // form options |
| 93 | + }); |
| 94 | + |
| 95 | + return ( |
| 96 | + <form {...form.props}> |
| 97 | + {/* TypeScript knows about textFieldProps! */} |
| 98 | + <TextField {...fields.email.textFieldProps} /> |
| 99 | + <TextField {...fields.password.textFieldProps} /> |
| 100 | + <button>Login</button> |
| 101 | + </form> |
| 102 | + ); |
| 103 | +} |
| 104 | +``` |
| 105 | + |
| 106 | +### `intentName?: string` |
| 107 | + |
| 108 | +The name of the submit button field that indicates the submission intent. Default is `'__intent__'`. |
| 109 | + |
| 110 | +This is an advanced option. You typically don't need to change this unless you have conflicts with existing field names. |
| 111 | + |
| 112 | +### `serialize(value: unknown) => string | string[] | File | File[] | null | undefined` |
| 113 | + |
| 114 | +A custom serialization function for converting form data. |
| 115 | + |
| 116 | +This is an advanced option. You typically don't need to change this unless you have special serialization requirements. |
| 117 | + |
| 118 | +## Tips |
| 119 | + |
| 120 | +### Conditional metadata based on field shape |
| 121 | + |
| 122 | +You can use TypeScript's conditional types to restrict custom metadata based on the field shape: |
| 123 | + |
| 124 | +```tsx |
| 125 | +function defineCustomMetadata<FieldShape, ErrorShape>( |
| 126 | + metadata: BaseMetadata<FieldShape, ErrorShape>, |
| 127 | +) { |
| 128 | + return { |
| 129 | + get dateRangePickerProps() { |
| 130 | + // Only available for field with start and end properties |
| 131 | + const rangeFields = metadata.getFieldset<{ |
| 132 | + start: string; |
| 133 | + end: string; |
| 134 | + }>(); |
| 135 | + |
| 136 | + return { |
| 137 | + startName: rangeFields.start.name, |
| 138 | + endName: rangeFields.end.name, |
| 139 | + defaultValue: { |
| 140 | + start: rangeFields.start.defaultValue, |
| 141 | + end: rangeFields.end.defaultValue, |
| 142 | + }, |
| 143 | + isInvalid: !metadata.valid, |
| 144 | + errors: metadata.errors?.map((error) => `${error}`), |
| 145 | + } satisfies Partial<React.ComponentProps<typeof DateRangePicker>>; |
| 146 | + }, |
| 147 | + }; |
| 148 | +} |
| 149 | + |
| 150 | +declare module '@conform-to/react/future' { |
| 151 | + interface CustomMetadata<FieldShape, ErrorShape> { |
| 152 | + // Make dateRangePickerProps only available if the field shape has start and end properties |
| 153 | + dateRangePickerProps: FieldShape extends { start: string; end: string } |
| 154 | + ? ReturnType< |
| 155 | + typeof defineCustomMetadata<FieldShape, ErrorShape> |
| 156 | + >['dateRangePickerProps'] |
| 157 | + : unknown; |
| 158 | + } |
| 159 | +} |
| 160 | +``` |
0 commit comments