https://github.com/jcoreio/zod-forms
A more seamless way to build React forms from Zod schemas
https://github.com/jcoreio/zod-forms
Last synced: 11 months ago
JSON representation
A more seamless way to build React forms from Zod schemas
- Host: GitHub
- URL: https://github.com/jcoreio/zod-forms
- Owner: jcoreio
- License: mit
- Created: 2024-07-12T05:53:27.000Z (almost 2 years ago)
- Default Branch: master
- Last Pushed: 2024-10-24T23:49:01.000Z (over 1 year ago)
- Last Synced: 2024-11-25T03:13:15.811Z (over 1 year ago)
- Language: TypeScript
- Homepage: https://jcoreio.github.io/zod-forms/
- Size: 1.17 MB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.md
Awesome Lists containing this project
README
# @jcoreio/zod-forms
A more seamless way to build React forms from Zod schemas
[](https://circleci.com/gh/jcoreio/zod-forms)
[](https://codecov.io/gh/jcoreio/zod-forms)
[](https://github.com/semantic-release/semantic-release)
[](http://commitizen.github.io/cz-cli/)
[](https://badge.fury.io/js/%40jcoreio%2Fzod-forms)
# Features
- 100% typesafe - Fully typechecked paths, input and output types for deeply nested fields
- Supports `z.string().optional()`, `z.string().nullable()`, `z.number()` etc in inputs out of the box
- Interprets blank inputs as `undefined` or `null` by default, depending on what the field schema
accepts
- Normalizes inputs on blur by default (e.g. with `z.string().blur()` you'll see the trim on blur)
- Supports Zod schemas with different input and output types (as long as you use
`zod-invertible` to specify how to format from output back to input)
- Allows you to programmatically set either input or output values
- Each step of a wizard form can declare its own submit handler independent from the enclosing
`` element. This enables animated transitions between steps without a separate
``s or submit button for each step.
# Limitations
- Designed specifically for Zod and React only
- Not currently focused on high performance/large form state like `final-form` or `react-hooks-form`
- No async validate outside of submit right now
# Quickstart
## Installation
```bash
pnpm i @jcoreio/zod-forms
```
or if you're using `npm`:
```bash
npm i --save @jcoreio/zod-forms
```
## Create a form schema
In this example, we'll have a `url` field that must be a valid URL.
Using `.trim()` ensures that the submitted value will be trimmed.
The displayed value will also be trimmed whenever the field is blurred.
```ts
import z from 'zod'
const schema = z.object({
url: z.string().trim().url(),
})
```
## Create a form
```ts
import { createZodForm } from '@jcoreio/zod-form'
const {
FormProvider,
// all of the following hooks can also be imported from '@jcoreio/zod-form',
// but the ones returned from `createZodForm` are already bound to the schema type
useInitialize,
useSubmit,
useFormStatus,
useHtmlField,
} = createZodForm({ schema })
```
## Create a field component
```ts
import { FieldPathForValue } from '@jcoreio/zod-form'
function FormInput({
field,
type,
...props
}: Omit, 'type'> & {
type: HTMLInputTypeAttribute
// This ensures that only fields that accept string, null or undefined
// as input can be passed to
field: FieldPathForValue
}) {
// This hook is designed to provide the smoothest integration with simple s.
const { input, meta } = useHtmlField({ field, type })
const inputRef = React.createRef()
const error = meta.touched || meta.submitFailed ? meta.error : undefined
React.useEffect(() => {
inputRef.current?.setCustomValidity(error || '')
}, [error])
return (
)
}
```
## Create the form component
```tsx
function MyForm() {
return (
// wraps in a React Context through which the
// hooks and fields access form state
)
}
function MyFormContent() {
// This hook initializes the form with the given values.
// The second argument is a dependency array -- the form will be reinitialized
// if any of the dependencies change, similar to React.useEffect.
useInitialize({ values: { url: 'http://localhost' } }, [])
// This hook sets your submit handler code, and returns an onSubmit handler to
// pass to a
const onSubmit = useSubmit({
onSubmit: async ({ url }) => {
alert(`Submitted! url value: ${url}`)
},
})
const { submitting, pristine } = useFormStatus()
return (
to the `url` field
field={myForm.get('url')}
type="text"
placeholder="URL"
/>
submit
)
}
```