@remix-validated-form/with-yup
Advanced tools
Comparing version 1.0.0 to 1.0.1
{ | ||
"name": "@remix-validated-form/with-yup", | ||
"version": "1.0.0", | ||
"version": "1.0.1", | ||
"browser": "./browser/index.js", | ||
"main": "./build/index.js", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/airjp73/remix-validated-form" | ||
}, | ||
"scripts": { | ||
@@ -11,4 +15,3 @@ "dev": "tsc --module ESNext --outDir ./browser --watch", | ||
"build:main": "tsc --module CommonJS --outDir ./build", | ||
"prepublishOnly": "cp ../../README.md ./README.md && npm run build", | ||
"postpublish": "rm ./README.md" | ||
"prepublishOnly": "npm run build" | ||
}, | ||
@@ -15,0 +18,0 @@ "peerDependencies": { |
248
README.md
@@ -1,247 +0,7 @@ | ||
# Remix Validated Form | ||
# @remix-validated-form/with-yup | ||
A form library built for [remix](https://remix.run) to make validation easy. | ||
Yup adapter for [remix-validated-form](https://github.com/airjp73/remix-validated-form). | ||
- Client-side, field-by-field validation (e.g. validate on blur) and form-level validation | ||
- Set default values for the entire form in one place | ||
- Re-use validation on the server | ||
- Show validation errors from the server even without JS | ||
- Detect if the current form is submitting when there are multiple forms on the page | ||
- Supports nested objects and arrays | ||
- Validation library agnostic | ||
## Docs | ||
# Demo | ||
https://user-images.githubusercontent.com/2811287/145734901-700a5085-a10b-4d89-88e1-5de9142b1e85.mov | ||
To run `sample-app`: | ||
``` | ||
git clone https://github.com/airjp73/remix-validated-form | ||
cd ./remix-validated-form | ||
yarn install | ||
yarn sample-app | ||
``` | ||
# Getting started | ||
## Install | ||
### Base package | ||
```bash | ||
npm install remix-validated-form | ||
``` | ||
### Validation library adapter | ||
There are official adapters available for `zod` and `yup`. | ||
If you're using a different library, | ||
see the [Validation library support](#validation-library-support) section below. | ||
- @remix-validated-form/with-zod | ||
- @remix-validated-form/with-yup | ||
```bash | ||
npm install @remix-validated-form/with-zod | ||
``` | ||
## Create an input component | ||
In order to display field errors or do field-by-field validation, | ||
it's recommended to incorporate this library into an input component using `useField`. | ||
```tsx | ||
import { useField } from "remix-validated-form"; | ||
type MyInputProps = { | ||
name: string; | ||
label: string; | ||
}; | ||
export const MyInput = ({ name, label }: InputProps) => { | ||
const { validate, clearError, defaultValue, error } = useField(name); | ||
return ( | ||
<div> | ||
<label htmlFor={name}>{label}</label> | ||
<input | ||
id={name} | ||
name={name} | ||
onBlur={validate} | ||
onChange={clearError} | ||
defaultValue={defaultValue} | ||
/> | ||
{error && <span className="my-error-class">{error}</span>} | ||
</div> | ||
); | ||
}; | ||
``` | ||
## Create a submit button component | ||
To best take advantage of the per-form submission detection, we can create a submit button component. | ||
```tsx | ||
import { useIsSubmitting } from "remix-validated-form"; | ||
export const MySubmitButton = () => { | ||
const isSubmitting = useIsSubmitting(); | ||
return ( | ||
<button type="submit" disabled={isSubmitting}> | ||
{isSubmitting ? "Submitting..." : "Submit"} | ||
</button> | ||
); | ||
}; | ||
``` | ||
## Use the form! | ||
Now that we have our components, making a form is easy! | ||
```tsx | ||
import { ActionFunction, LoaderFunction, redirect, useLoaderData } from "remix"; | ||
import * as yup from "yup"; | ||
import { validationError, ValidatedForm, withYup } from "remix-validated-form"; | ||
import { MyInput, MySubmitButton } from "~/components/Input"; | ||
// Using yup in this example, but you can use anything | ||
const validator = withYup( | ||
yup.object({ | ||
firstName: yup.string().label("First Name").required(), | ||
lastName: yup.string().label("Last Name").required(), | ||
email: yup.string().email().label("Email").required(), | ||
}) | ||
); | ||
export const action: ActionFunction = async ({ request }) => { | ||
const fieldValues = validator.validate(await request.formData()); | ||
if (fieldValues.error) return validationError(fieldValues.error); | ||
const { firstName, lastName, email } = fieldValues.data; | ||
// Do something with correctly typed values; | ||
return redirect("/"); | ||
}; | ||
export const loader: LoaderFunction = () => { | ||
return { | ||
defaultValues: { | ||
firstName: "Jane", | ||
lastName: "Doe", | ||
email: "jane.doe@example.com", | ||
}, | ||
}; | ||
}; | ||
export default function MyForm() { | ||
const { defaultValues } = useLoaderData(); | ||
return ( | ||
<ValidatedForm | ||
validator={validator} | ||
method="post" | ||
defaultValues={defaultValues} | ||
> | ||
<MyInput name="firstName" label="First Name" /> | ||
<MyInput name="lastName" label="Last Name" /> | ||
<MyInput name="email" label="Email" /> | ||
<MySubmitButton /> | ||
</ValidatedForm> | ||
); | ||
} | ||
``` | ||
## Nested objects and arrays | ||
You can use nested objects and arrays by using a period (`.`) or brackets (`[]`) for the field names. | ||
```tsx | ||
export default function MyForm() { | ||
const { defaultValues } = useLoaderData(); | ||
return ( | ||
<ValidatedForm | ||
validator={validator} | ||
method="post" | ||
defaultValues={defaultValues} | ||
> | ||
<MyInput name="firstName" label="First Name" /> | ||
<MyInput name="lastName" label="Last Name" /> | ||
<MyInput name="address.street" label="Street" /> | ||
<MyInput name="address.city" label="City" /> | ||
<MyInput name="phones[0].type" label="Phone 1 Type" /> | ||
<MyInput name="phones[0].number" label="Phone 1 Number" /> | ||
<MyInput name="phones[1].type" label="Phone 2 Type" /> | ||
<MyInput name="phones[1].number" label="Phone 2 Number" /> | ||
<MySubmitButton /> | ||
</ValidatedForm> | ||
); | ||
} | ||
``` | ||
# Validation Library Support | ||
There are official adapters available for `zod` and `yup` , | ||
but you can easily support whatever library you want by creating your own adapter. | ||
And if you create an adapter for a library, feel free to make a PR on this repository 😊 | ||
## Creating an adapter | ||
Any object that conforms to the `Validator` type can be passed into the the `ValidatedForm`'s `validator` prop. | ||
```ts | ||
type FieldErrors = Record<string, string>; | ||
type ValidationResult<DataType> = | ||
| { data: DataType; error: undefined } | ||
| { error: FieldErrors; data: undefined }; | ||
type ValidateFieldResult = { error?: string }; | ||
type Validator<DataType> = { | ||
validate: (unvalidatedData: unknown) => ValidationResult<DataType>; | ||
validateField: ( | ||
unvalidatedData: unknown, | ||
field: string | ||
) => ValidateFieldResult; | ||
}; | ||
``` | ||
In order to make an adapter for your validation library of choice, | ||
you can create a function that accepts a schema from the validation library and turns it into a validator. | ||
Note the use of `createValidator`. | ||
It takes care of unflattening the data for nested objects and arrays | ||
since the form doesn't know anything about object and arrays and this should be handled by the adapter. | ||
For more on this you can check the implementations for `withZod` and `withYup`. | ||
The out-of-the-box support for `yup` in this library works like this: | ||
```ts | ||
export const withYup = <Schema extends AnyObjectSchema>( | ||
validationSchema: Schema | ||
// For best result with Typescript, we should type the `Validator` we return based on the provided schema | ||
): Validator<InferType<Schema>> => | ||
createValidator({ | ||
validate: (unvalidatedData) => { | ||
// Validate with yup and return the validated & typed data or the error | ||
if (isValid) return { data: { field1: "someValue" }, error: undefined }; | ||
else return { error: { field1: "Some error!" }, data: undefined }; | ||
}, | ||
validateField: (unvalidatedData, field) => { | ||
// Validate the specific field with yup | ||
if (isValid) return { error: undefined }; | ||
else return { error: "Some error" }; | ||
}, | ||
}); | ||
``` | ||
# Frequenty Asked Questions | ||
## Why are my fields triggering the native HTML validations before `remix-validated-form` ones? | ||
This is happening because you or the library you are using is passing the `required` attribute to the fields. | ||
This library doesn't take care of eliminating them and it's up to the user how they want to manage the validation errors. | ||
If you wan't to disable all native HTML validations you can add `noValidate` to `<ValidatedForm>`. | ||
We recommend this approach since the validation will still work even if JS is disabled. | ||
The docs are located a [remix-validated-form.io](https://www.remix-validated-form.io). |
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
0
5690
7