Skip to content

Commit

Permalink
docs: update zod instructions (#237)
Browse files Browse the repository at this point in the history
  • Loading branch information
edmundhung authored Jul 22, 2023
1 parent aa33c23 commit 436c39f
Show file tree
Hide file tree
Showing 16 changed files with 374 additions and 354 deletions.
14 changes: 8 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# CONFORM [![latest release](https://img.shields.io/github/v/release/edmundhung/conform?display_name=tag&sort=semver&style=flat-square&labelColor=000&color=2a4233)](https://github.com/edmundhung/conform/releases) [![GitHub license](https://img.shields.io/github/license/edmundhung/conform?style=flat-square&labelColor=000&color=2a4233)](https://github.com/edmundhung/conform/blob/main/LICENSE)
# CONFORM [![latest release](https://img.shields.io/github/v/release/edmundhung/conform?display_name=tag&sort=semver&style=flat-square&labelColor=333&color=000)](https://github.com/edmundhung/conform/releases) [![GitHub license](https://img.shields.io/github/license/edmundhung/conform?style=flat-square&labelColor=333&color=000)](https://github.com/edmundhung/conform/blob/main/LICENSE)

A progressive enhancement first form validation library for Remix and React Router

### Highlights

- Focused on progressive enhancement by default
- Progressive enhancement first APIs
- Automatic type coercion with Zod
- Simplifed integration through event delegation
- Server first validation with Zod / Yup schema support
- Field name inference with type checking
- Field name inference
- Focus management
- Accessibility support
- About 5kb compressed
Expand All @@ -25,8 +25,10 @@ import { z } from 'zod';
import { authenticate } from '~/auth';

const schema = z.object({
email: z.string().min(1, 'Email is required').email('Email is invalid'),
password: z.string().min(1, 'Password is required'),
email: z
.string({ required_error: 'Email is required' })
.email('Email is invalid'),
password: z.string({ required_error: 'Password is required' }),
});

export async function action({ request }: ActionArgs) {
Expand Down
77 changes: 54 additions & 23 deletions docs/complex-structures.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,29 +17,44 @@ Conform support both nested object and array by leveraging a naming convention o

**Conform** uses the `object.property` and `array[index]` syntax to denote data structure. These notations could be combined for nest list as well. e.g. `tasks[0].content`.

The form data should be parsed using the Conform [parse](/packages/conform-react/README.md#parse) helper to resolve each data path and reconstruct the data structure accordingly.
The form data should be parsed using the Conform [parse](/packages/conform-zod/README.md#parse) helper to resolve each data path and reconstruct the data structure accordingly.

```ts
import { parse } from '@conform-to/react';

const formData = new FormData();
import { parse } from '@conform-to/zod';

// If the form data has an entry `['tasks[0].content', 'Hello World']`
const submission = parse(formData);
const submission = parse(formData, {
/* ... */
});

// The submission payload will be `{ tasks: [{ content: 'Hello World' }] }`
// The submission payload will become `{ tasks: [{ content: 'Hello World' }] }`
console.log(submission.payload);
```

## Nested Object

When you need to set up nested fields, you can pass the parent field config to the[useFieldset](/packages/conform-react/README.md#usefieldset) hook to get access to each child field with name infered automatically.
When you need to set up nested fields, you can pass the parent field config to the [useFieldset](/packages/conform-react/README.md#usefieldset) hook to get access to each child field with name infered automatically.

```tsx
import { useForm, useFieldset } from '@conform-to/react';
import { parse } from '@conform-to/zod';
import { z } from 'zod';

const schema = z.object({
address: z.object({
street: z.string(),
zipcode: z.string(),
city: z.string(),
country: z.string(),
}),
});

function Example() {
const [form, { address }] = useForm<Schema>();
const [form, { address }] = useForm({
onValidate({ formData }) {
return parse(formData, { schema });
},
});
const { city, zipcode, street, country } = useFieldset(form.ref, address);

return (
Expand All @@ -60,13 +75,23 @@ function Example() {

## Array

When you need to setup a list of fields, you can pass the parent field config to the[useFieldList](/packages/conform-react/README.md#usefieldlist) hook to get access to each item field with name infered automatically as well.
When you need to setup a list of fields, you can pass the parent field config to the [useFieldList](/packages/conform-react/README.md#usefieldlist) hook to get access to each item field with name infered automatically as well.

```tsx
import { useForm, useFieldList } from '@conform-to/react';
import { parse } from '@conform-to/zod';
import { z } from 'zod';

const schema = z.object({
tasks: z.array(z.string()),
});

function Example() {
const [form, { tasks }] = useForm();
const [form, { tasks }] = useForm({
onValidate({ formData }) {
return parse(formData, { schema });
},
});
const list = useFieldList(form.ref, tasks);

return (
Expand All @@ -85,7 +110,7 @@ function Example() {
}
```

For information about modifying list (e.g. append / remove / reorder), see the [Modifying a list](/docs/intent-button.md#modifying-a-list) section.
For information about modifying list (e.g. append / remove / reorder), see the [list intent](/docs/intent-button.md#list-intent) section.

## Nested List

Expand All @@ -94,18 +119,24 @@ You can also combine both [useFieldset](/packages/conform-react/README.md#usefie
```tsx
import type { FieldConfig } from '@conform-to/react';
import { useForm, useFieldset, useFieldList } from '@conform-to/react';

interface Todo {
title: string;
notes: string;
}

interface Schema {
todos: Todo[];
}
import { parse } from '@conform-to/zod';
import { z } from 'zod';

const schema = z.object({
todos: z.array(
z.object({
title: z.string(),
notes: z.string(),
}),
),
});

function Example() {
const [form, { tasks }] = useForm();
const [form, { tasks }] = useForm({
onValidate({ formData }) {
return parse(formData, { schema });
},
});
const todos = useFieldList(form.ref, tasks);

return (
Expand All @@ -114,15 +145,15 @@ function Example() {
{todos.map((todo) => (
<li key={todo.key}>
{/* Pass each item config to TodoFieldset */}
<TodoFieldset {...todo} />
<TodoFieldset config={todo} />
</li>
))}
</ul>
</form>
);
}

function TodoFieldset(config: FieldConfig<Todo>) {
function TodoFieldset(props: { config: FieldConfig<Todo> }) {
const ref = useRef<HTMLFieldsetElement>(null);
// Both useFieldset / useFieldList accept form or fieldset ref
const { title, notes } = useFieldset(ref, config);
Expand Down
14 changes: 7 additions & 7 deletions docs/intent-button.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ A submit button can contribute to the form data when it triggers the submission
## On this page

- [Submission Intent](#submission-intent)
- [Modifying a list](#modifying-a-list)
- [Validation](#validation)
- [Triggering an intent](#triggering-an-intent)
- [List intent](#list-intent)
- [Validate intent](#validate-intent)
- [Triggering intent](#triggering-intent)

<!-- /aside -->

Expand Down Expand Up @@ -77,7 +77,7 @@ function Product() {
}
```

### Modifying a list
### List intent

Conform provides built-in [list](/packages/conform-react/README.md#list) intent button builder for you to modify a list of fields.

Expand Down Expand Up @@ -107,7 +107,7 @@ export default function Todos() {
}
```

## Validation
## Validate intent

A validation can be triggered by configuring a button with the [validate](/packages/conform-react/README.md#validate) intent.

Expand All @@ -128,7 +128,7 @@ export default function Todos() {
}
```

## Triggering an intent
## Triggering intent

Sometimes, it could be useful to trigger an intent without requiring users to click on the intent button. We can achieve it by capturing the button element with `useRef` and triggering the intent with `button.click()`

Expand Down Expand Up @@ -203,4 +203,4 @@ export default function Todos() {
}
```

Conform is also utilizing the requestIntent helper to trigger the validate intent based on input and blur event.
Conform is also utilizing the `requestIntent` helper to trigger the `validate` intent on input or blur event.
Loading

0 comments on commit 436c39f

Please sign in to comment.