From aa288608ffac55364234548a316cd2ff58e6e624 Mon Sep 17 00:00:00 2001 From: Pascal Baljet Date: Wed, 6 Aug 2025 18:07:12 +0200 Subject: [PATCH 1/5] wip --- resources/js/Pages/forms.jsx | 674 +++++++++++++++++++++++++++++++++++ 1 file changed, 674 insertions(+) diff --git a/resources/js/Pages/forms.jsx b/resources/js/Pages/forms.jsx index 2658a39b..844e67d7 100644 --- a/resources/js/Pages/forms.jsx +++ b/resources/js/Pages/forms.jsx @@ -7,6 +7,7 @@ export const meta = { { url: '#submitting-forms', name: 'Submitting forms' }, { url: '#server-side-validation', name: 'Server-side validation' }, { url: '#form-helper', name: 'Form helper' }, + { url: '#form-component', name: 'Form component' }, { url: '#file-uploads', name: 'File uploads' }, { url: '#xhr-fetch-submissions', name: 'XHR / fetch submissions' }, ], @@ -1005,6 +1006,679 @@ export default function () { }, ]} /> +

Form component

+

+ As an alternative to the useForm helper, Inertia provides a <Form> component that + offers a declarative approach to form handling. At its simplest, the component behaves much like a classic HTML + form, but with all the benefits of Inertia's SPA-like navigation. While useForm() gives you programmatic + control over form data and submission logic, the <Form> component is ideal when you prefer a + more HTML-like, declarative approach with minimal JavaScript. +

+ + + + + + `, + }, + { + name: 'React', + language: 'jsx', + code: dedent` +
+ + + +
+ `, + }, + { + name: 'Svelte', + language: 'html', + code: dedent` +
+ + + +
+ `, + }, + ]} + /> +

+ The component also supports advanced use cases, including nested data structures, file uploads, and dotted key notation: +

+ + + + + + + + `, + }, + { + name: 'React', + language: 'jsx', + code: dedent` +
+ + + + + +
+ `, + }, + { + name: 'Svelte', + language: 'html', + code: dedent` +
+ + + + + +
+ `, + }, + ]} + /> +

+ You can pass a transform prop to modify the form data before submission. This is useful for + injecting additional fields or transforming existing data, although hidden inputs work too: +

+ + + + + `, + }, + { + name: 'React', + language: 'jsx', + code: dedent` +
({ ...data, user_id: 123 })} + > + + +
+ `, + }, + { + name: 'Svelte', + language: 'html', + code: dedent` +
({ ...data, user_id: 123 })} + > + + +
+ `, + }, + ]} + /> +

Slot props

+

+ Just like the useForm() helper, the <Form> component exposes reactive state + and helper methods through its default slot: +

+ + +
{{ errors.name }}
+ + + +
User created successfully!
+ + `, + }, + { + name: 'React', + language: 'jsx', + code: dedent` +
+ {({ + errors, + hasErrors, + processing, + progress, + wasSuccessful, + recentlySuccessful, + setError, + clearErrors, + isDirty, + reset, + submit, + }) => ( + <> + + {errors.name &&
{errors.name}
} + + + + {wasSuccessful &&
User created successfully!
} + + )} +
+ `, + }, + { + name: 'Svelte 4', + language: 'html', + code: dedent` +
+ + {#if errors.name} +
{errors.name}
+ {/if} + + + + {#if wasSuccessful} +
User created successfully!
+ {/if} +
+ `, + }, + { + name: 'Svelte 5', + language: 'html', + code: dedent` +
+ {#snippet children({ + errors, + hasErrors, + processing, + progress, + wasSuccessful, + recentlySuccessful, + setError, + clearErrors, + isDirty, + reset, + submit, + })} + + {#if errors.name} +
{errors.name}
+ {/if} + + + + {#if wasSuccessful} +
User created successfully!
+ {/if} + {/snippet} +
+ `, + }, + ]} + /> +

Props and options

+

+ In addition to action and method, the <Form> component accepts + several props. Many of them are identical to the options available in Inertia's{' '} + visit options: +

+ + + + + `, + }, + { + name: 'React', + language: 'jsx', + code: dedent` +
({ ...data, timestamp: Date.now() })} + options={{ + preserveScroll: true, + preserveState: true, + preserveUrl: true, + replace: true, + only: ['users', 'flash'], + except: ['secret'], + reset: ['page'], + }} + > + + +
+ `, + }, + { + name: 'Svelte', + language: 'html', + code: dedent` +
({ ...data, timestamp: Date.now() })} + options={{ + preserveScroll: true, + preserveState: true, + preserveUrl: true, + replace: true, + only: ['users', 'flash'], + except: ['secret'], + reset: ['page'], + }} + > + + +
+ `, + }, + ]} + /> +

+ Some props are intentionally grouped under options instead of being top-level to avoid confusion. + For example, only, except, and reset relate to partial reloads, + not partial submissions. The general rule: top-level props are for the form submission itself, while{' '} + options control how Inertia handles the subsequent visit. +

+

Events

+

+ The <Form> component emits the same events as useForm(), except + the ones related to prefetching: +

+ + + + + `, + }, + { + name: 'React', + language: 'jsx', + code: dedent` +
+ + +
+ `, + }, + { + name: 'Svelte 4', + language: 'html', + code: dedent` +
+ + +
+ `, + }, + { + name: 'Svelte 5', + language: 'html', + code: dedent` +
+ + +
+ `, + }, + ]} + /> +

Dotted key notation

+

+ The <Form> component supports dotted key notation for creating nested objects from flat + input names. This provides a convenient way to structure form data without needing complex JavaScript logic. +

+ + + + + + + `, + }, + { + name: 'React', + language: 'jsx', + code: dedent` +
+ + + + +
+ `, + }, + { + name: 'Svelte', + language: 'html', + code: dedent` +
+ + + + +
+ `, + }, + ]} + /> +

+ The above example would generate the following data structure: +

+ +

+ If you need literal dots in your field names (not as nested object separators), you can escape them using + backslashes: +

+ + + + + + `, + }, + { + name: 'React', + language: 'jsx', + code: dedent` +
+ + + +
+ `, + }, + { + name: 'Svelte', + language: 'html', + code: dedent` +
+ + + +
+ `, + }, + ]} + /> +

+ This would result in: +

+ +

+ When using dotted keys or arrays, validation errors follow the same structure. You can access errors for + specific array indices or nested fields: +

+ + +
{{ errors['tags.0'] }}
+ + +
{{ errors['user.name'] }}
+ + `, + }, + { + name: 'React', + language: 'jsx', + code: dedent` +
+ {({ errors }) => ( + <> + + {errors['tags.0'] &&
{errors['tags.0']}
} + + + {errors['user.name'] &&
{errors['user.name']}
} + + )} +
+ `, + }, + { + name: 'Svelte 4', + language: 'html', + code: dedent` +
+ + {#if errors['tags.0']} +
{errors['tags.0']}
+ {/if} + + + {#if errors['user.name']} +
{errors['user.name']}
+ {/if} +
+ `, + }, + { + name: 'Svelte 5', + language: 'html', + code: dedent` +
+ {#snippet children({ errors })} + + {#if errors['tags.0']} +
{errors['tags.0']}
+ {/if} + + + {#if errors['user.name']} +
{errors['user.name']}
+ {/if} + {/snippet} +
+ `, + }, + ]} + />

File uploads

When making requests or form submissions that include files, Inertia will automatically convert the request data From 2d6d24d4f9970c80c8e1d93b4d204e74df8af7b9 Mon Sep 17 00:00:00 2001 From: Pascal Baljet Date: Wed, 6 Aug 2025 18:09:37 +0200 Subject: [PATCH 2/5] wip --- resources/js/Pages/forms.jsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/resources/js/Pages/forms.jsx b/resources/js/Pages/forms.jsx index 844e67d7..75ebfb58 100644 --- a/resources/js/Pages/forms.jsx +++ b/resources/js/Pages/forms.jsx @@ -1170,6 +1170,7 @@ export default function () { recentlySuccessful, setError, clearErrors, + resetAndClearErrors, isDirty, reset, submit, @@ -1200,6 +1201,7 @@ export default function () { recentlySuccessful, setError, clearErrors, + resetAndClearErrors, isDirty, reset, submit, @@ -1233,6 +1235,7 @@ export default function () { let:recentlySuccessful let:setError let:clearErrors + let:resetAndClearErrors let:isDirty let:reset let:submit @@ -1266,6 +1269,7 @@ export default function () { recentlySuccessful, setError, clearErrors, + resetAndClearErrors, isDirty, reset, submit, From 04e64a25ae2f8529149e05b8b18b6bdd78587c25 Mon Sep 17 00:00:00 2001 From: Pascal Baljet Date: Thu, 7 Aug 2025 09:59:55 +0200 Subject: [PATCH 3/5] wip --- resources/js/Pages/forms.jsx | 140 ++++++++++++++++------------------- 1 file changed, 62 insertions(+), 78 deletions(-) diff --git a/resources/js/Pages/forms.jsx b/resources/js/Pages/forms.jsx index 75ebfb58..2c99aa37 100644 --- a/resources/js/Pages/forms.jsx +++ b/resources/js/Pages/forms.jsx @@ -1012,7 +1012,7 @@ export default function () { offers a declarative approach to form handling. At its simplest, the component behaves much like a classic HTML form, but with all the benefits of Inertia's SPA-like navigation. While useForm() gives you programmatic control over form data and submission logic, the <Form> component is ideal when you prefer a - more HTML-like, declarative approach with minimal JavaScript. + more HTML-like, declarative approach.

+

+ The errors object uses dotted notation for nested fields, allowing you to display validation + messages for complex form structures: +

+ + +
{{ errors['user.name'] }}
+ + `, + }, + { + name: 'React', + language: 'jsx', + code: dedent` +
+ {({ errors }) => ( + <> + + {errors['user.name'] &&
{errors['user.name']}
} + + )} +
+ `, + }, + { + name: 'Svelte 4', + language: 'html', + code: dedent` +
+ + {#if errors['user.name']} +
{errors['user.name']}
+ {/if} +
+ `, + }, + { + name: 'Svelte 5', + language: 'html', + code: dedent` +
+ {#snippet children({ errors })} + + {#if errors['user.name']} +
{errors['user.name']}
+ {/if} + {/snippet} +
+ `, + }, + ]} + />

Props and options

In addition to action and method, the <Form> component accepts @@ -1391,8 +1449,8 @@ export default function () {

Events

- The <Form> component emits the same events as useForm(), except - the ones related to prefetching: + The <Form> component emits all the standard visit events for form + submissions, plus a cancelToken event for handling form cancellation:

Dotted key notation

The <Form> component supports dotted key notation for creating nested objects from flat - input names. This provides a convenient way to structure form data without needing complex JavaScript logic. + input names. This provides a convenient way to structure form data.

-

- When using dotted keys or arrays, validation errors follow the same structure. You can access errors for - specific array indices or nested fields: -

- - -
{{ errors['tags.0'] }}
- - -
{{ errors['user.name'] }}
- - `, - }, - { - name: 'React', - language: 'jsx', - code: dedent` -
- {({ errors }) => ( - <> - - {errors['tags.0'] &&
{errors['tags.0']}
} - - - {errors['user.name'] &&
{errors['user.name']}
} - - )} -
- `, - }, - { - name: 'Svelte 4', - language: 'html', - code: dedent` -
- - {#if errors['tags.0']} -
{errors['tags.0']}
- {/if} - - - {#if errors['user.name']} -
{errors['user.name']}
- {/if} -
- `, - }, - { - name: 'Svelte 5', - language: 'html', - code: dedent` -
- {#snippet children({ errors })} - - {#if errors['tags.0']} -
{errors['tags.0']}
- {/if} - - - {#if errors['user.name']} -
{errors['user.name']}
- {/if} - {/snippet} -
- `, - }, - ]} - />

File uploads

When making requests or form submissions that include files, Inertia will automatically convert the request data From e776c6d8a6c48927ae226ceeb4a978c57efa5713 Mon Sep 17 00:00:00 2001 From: Pascal Baljet Date: Thu, 7 Aug 2025 10:31:37 +0200 Subject: [PATCH 4/5] restructure --- resources/js/Pages/forms.jsx | 2107 +++++++++++++++++----------------- 1 file changed, 1053 insertions(+), 1054 deletions(-) diff --git a/resources/js/Pages/forms.jsx b/resources/js/Pages/forms.jsx index 2c99aa37..232052cf 100644 --- a/resources/js/Pages/forms.jsx +++ b/resources/js/Pages/forms.jsx @@ -4,10 +4,11 @@ import dedent from 'dedent-js' export const meta = { title: 'Forms', links: [ - { url: '#submitting-forms', name: 'Submitting forms' }, - { url: '#server-side-validation', name: 'Server-side validation' }, - { url: '#form-helper', name: 'Form helper' }, { url: '#form-component', name: 'Form component' }, + { url: '#form-helper', name: 'Form helper' }, + { url: '#server-side-responses', name: 'Server-side responses' }, + { url: '#server-side-validation', name: 'Server-side validation' }, + { url: '#manual-form-submissions', name: 'Manual form submissions' }, { url: '#file-uploads', name: 'File uploads' }, { url: '#xhr-fetch-submissions', name: 'XHR / fetch submissions' }, ], @@ -17,11 +18,10 @@ export default function () { return ( <>

Forms

-

Submitting forms

+

Form component

- While it's possible to make classic HTML form submissions with Inertia, it's not recommended since they cause - full-page reloads. Instead, it's better to intercept form submissions and then make the{' '} - request using Inertia. + Inertia provides a <Form> component that behaves much like a classic HTML form, but uses + Inertia under the hood to avoid full page reloads. This is the simplest way to get started with forms in Inertia:

- import { reactive } from 'vue' - import { router } from '@inertiajs/vue3' - - const form = reactive({ - first_name: null, - last_name: null, - email: null, - }) - - function submit() { - router.post('/users', form) - } - - - +
+ + + +
`, }, { name: 'React', language: 'jsx', code: dedent` - import { useState } from 'react' - import { router } from '@inertiajs/react' - - export default function Edit() { - const [values, setValues] = useState({ - first_name: "", - last_name: "", - email: "", - }) - - function handleChange(e) { - const key = e.target.id; - const value = e.target.value - setValues(values => ({ - ...values, - [key]: value, - })) - } - - function handleSubmit(e) { - e.preventDefault() - router.post('/users', values) - } - - return ( -
- - - - - - - -
- ) - } +
+ + + +
`, }, { - name: 'Svelte 4', + name: 'Svelte', language: 'html', code: dedent` - - -
- - - - - - - - - - -
+
+ + + +
`, }, + ]} + /> +

+ The component also supports advanced use cases, including nested data structures, file uploads, and dotted key notation: +

+ + + + + + + + `, + }, + { + name: 'React', + language: 'jsx', + code: dedent` +
+ + + + + +
+ `, + }, + { + name: 'Svelte', language: 'html', code: dedent` - - -
- - - - - - - - - - -
+
+ + + + + +
`, }, ]} />

- As you may have noticed in the example above, when using Inertia, you don't typically need to inspect form - responses client-side like you would when making XHR / fetch requests manually. -

-

- Instead, your server-side route / controller typically issues a redirect response. And, - Of course, there is nothing stopping you from redirecting the user right back to the page they were previously - on. Using this approach, handling Inertia form submissions feels very similar to handling classic HTML form - submissions. + You can pass a transform prop to modify the form data before submission. This is useful for + injecting additional fields or transforming existing data, although hidden inputs work too:

User::all(), - ]); - } - - public function store(Request $request) - { - User::create($request->validate([ - 'first_name' => ['required', 'max:50'], - 'last_name' => ['required', 'max:50'], - 'email' => ['required', 'max:50', 'email'], - ])); - - return to_route('users.index'); - } - } +
+ + +
+ `, + }, + { + name: 'React', + language: 'jsx', + code: dedent` +
({ ...data, user_id: 123 })} + > + + +
+ `, + }, + { + name: 'Svelte', + language: 'html', + code: dedent` +
({ ...data, user_id: 123 })} + > + + +
`, }, ]} /> -

Server-side validation

-

- Handling server-side validation errors in Inertia works a little different than handling errors from manual XHR - / fetch requests. When making XHR / fetch requests, you typically inspect the response for a 422{' '} - status code and manually update the form's error state. -

-

- However, when using Inertia, a 422 response is never returned by your server. Instead, as we saw in - the example above, your routes / controllers will typically return a redirect response - much like a classic, - full-page form submission. -

-

- For a full discussion on handling and displaying validation errors with Inertia, please consult the{' '} - validation documentation. -

-

Form helper

+

Slot props

- Since working with forms is so common, Inertia includes a form helper designed to help reduce the amount of - boilerplate code needed for handling typical form submissions. + The <Form> component exposes reactive state and helper methods through its default slot, + giving you access to form processing state, errors, and utility functions:

- import { useForm } from '@inertiajs/vue3' +
+ +
{{ errors.name }}
- const form = useForm({ - email: null, - password: null, - remember: false, - }) - + - +
User created successfully!
+
`, }, { name: 'React', language: 'jsx', code: dedent` - import { useForm } from '@inertiajs/react' - - const { data, setData, post, processing, errors } = useForm({ - email: '', - password: '', - remember: false, - }) +
+ {({ + errors, + hasErrors, + processing, + progress, + wasSuccessful, + recentlySuccessful, + setError, + clearErrors, + resetAndClearErrors, + isDirty, + reset, + submit, + }) => ( + <> + + {errors.name &&
{errors.name}
} - function submit(e) { - e.preventDefault() - post('/login') - } + - return ( - - setData('email', e.target.value)} /> - {errors.email &&
{errors.email}
} - setData('password', e.target.value)} /> - {errors.password &&
{errors.password}
} - setData('remember', e.target.checked)} /> Remember Me - -
- ) + {wasSuccessful &&
User created successfully!
} + + )} + `, }, { name: 'Svelte 4', language: 'html', code: dedent` - + -
- - {#if $form.errors.email} -
{$form.errors.email}
- {/if} - - {#if $form.errors.password} -
{$form.errors.password}
+ {#if wasSuccessful} +
User created successfully!
{/if} - Remember Me - -
+ `, }, { name: 'Svelte 5', - language: 'jsx', + language: 'html', code: dedent` - + -
- - {#if $form.errors.email} -
{$form.errors.email}
- {/if} - - {#if $form.errors.password} -
{$form.errors.password}
- {/if} - Remember Me - -
+ {#if wasSuccessful} +
User created successfully!
+ {/if} + {/snippet} + `, }, ]} />

- To submit the form, you may use the get, post, put, patch{' '} - and delete methods. + The errors object uses dotted notation for nested fields, allowing you to display validation + messages for complex form structures:

+ +
{{ errors['user.name'] }}
+ `, }, { name: 'React', - language: 'js', + language: 'jsx', code: dedent` - const { submit, get, post, put, patch, delete: destroy } = useForm({ ... }) - - submit(method, url, options) - get(url, options) - post(url, options) - put(url, options) - patch(url, options) - destroy(url, options) +
+ {({ errors }) => ( + <> + + {errors['user.name'] &&
{errors['user.name']}
} + + )} +
`, }, { - name: 'Svelte', - language: 'js', + name: 'Svelte 4', + language: 'html', code: dedent` - $form.submit(method, url, options) - $form.get(url, options) - $form.post(url, options) - $form.put(url, options) - $form.patch(url, options) - $form.delete(url, options) +
+ + {#if errors['user.name']} +
{errors['user.name']}
+ {/if} +
+ `, + }, + { + name: 'Svelte 5', + language: 'html', + code: dedent` +
+ {#snippet children({ errors })} + + {#if errors['user.name']} +
{errors['user.name']}
+ {/if} + {/snippet} +
`, }, ]} /> +

Props and options

- The submit methods support all of the typical visit options, such as{' '} - preserveState, preserveScroll, and event callbacks, which can be helpful for - performing tasks on successful form submissions. For example, you might use the onSuccess callback - to reset inputs to their original state. + In addition to action and method, the <Form> component accepts + several props. Many of them are identical to the options available in Inertia's{' '} + visit options:

form.reset('password'), - }) +
+ + +
`, }, { name: 'React', - language: 'js', + language: 'jsx', code: dedent` - const { post, reset } = useForm({ ... }) - - post('/profile', { - preserveScroll: true, - onSuccess: () => reset('password'), - }) +
({ ...data, timestamp: Date.now() })} + options={{ + preserveScroll: true, + preserveState: true, + preserveUrl: true, + replace: true, + only: ['users', 'flash'], + except: ['secret'], + reset: ['page'], + }} + > + + +
`, }, { name: 'Svelte', - language: 'js', + language: 'html', code: dedent` - $form.post('/profile', { - preserveScroll: true, - onSuccess: () => $form.reset('password'), - }) +
({ ...data, timestamp: Date.now() })} + options={{ + preserveScroll: true, + preserveState: true, + preserveUrl: true, + replace: true, + only: ['users', 'flash'], + except: ['secret'], + reset: ['page'], + }} + > + + +
`, }, ]} />

- If you need to modify the form data before it's sent to the server, you can do so via the{' '} - transform() method. + Some props are intentionally grouped under options instead of being top-level to avoid confusion. + For example, only, except, and reset relate to partial reloads, + not partial submissions. The general rule: top-level props are for the form submission itself, while{' '} + options control how Inertia handles the subsequent visit. +

+

Events

+

+ The <Form> component emits all the standard visit events for form + submissions, plus a cancelToken event for handling form cancellation:

({ - ...data, - remember: data.remember ? 'on' : '', - })) - .post('/login') +
+ + +
`, }, { name: 'React', - language: 'js', + language: 'jsx', code: dedent` - const { transform } = useForm({ ... }) - - transform((data) => ({ - ...data, - remember: data.remember ? 'on' : '', - })) +
+ + +
`, }, { - name: 'Svelte', - language: 'js', + name: 'Svelte 4', + language: 'html', code: dedent` - $form - .transform((data) => ({ - ...data, - remember: data.remember ? 'on' : '', - })) - .post('/login') +
+ + +
+ `, + }, + { + name: 'Svelte 5', + language: 'html', + code: dedent` +
+ + +
`, }, ]} /> +

Dotted key notation

- You can use the processing property to track if a form is currently being submitted. This can be - helpful for preventing double form submissions by disabling the submit button. + The <Form> component supports dotted key notation for creating nested objects from flat + input names. This provides a convenient way to structure form data.

Submit +
+ + + + +
`, }, { name: 'React', language: 'jsx', code: dedent` - const { processing } = useForm({ ... }) - - +
+ + + + +
`, }, { name: 'Svelte', - language: 'jsx', + language: 'html', code: dedent` - +
+ + + + +
`, }, ]} />

- If your form is uploading files, the current progress event is available via the progress property, - allowing you to easily display the upload progress. + The above example would generate the following data structure: +

+ +

+ If you need literal dots in your field names (not as nested object separators), you can escape them using + backslashes:

- {{ form.progress.percentage }}% - +
+ + + +
`, }, { name: 'React', language: 'jsx', code: dedent` - const { progress } = useForm({ ... }) - - {progress && ( - - {progress.percentage}% - - )} +
+ + + +
`, }, { name: 'Svelte', - language: 'jsx', + language: 'html', code: dedent` - {#if $form.progress} - - {$form.progress.percentage}% - - {/if} +
+ + + +
`, }, ]} />

- If there are form validation errors, they are available via the errors property. When building - Laravel powered Inertia applications, form errors will automatically be populated when your application throws - instances of ValidationException, such as when using {'$request->validate()'}. + This would result in:

{{ form.errors.email }} - `, - }, - { - name: 'React', - language: 'jsx', - code: dedent` - const { errors } = useForm({ ... }) - - {errors.email &&
{errors.email}
} - `, - }, - { - name: 'Svelte', - language: 'jsx', + name: 'JSON', + language: 'json', code: dedent` - {#if $form.errors.email} -
{$form.errors.email}
- {/if} + { + "app.name": "My Application", + "settings": { + "theme.mode": "dark" + } + } `, }, ]} /> - - For a more thorough discussion of form validation and errors, please consult the{' '} - validation documentation. - +

Form helper

- To determine if a form has any errors, you may use the hasErrors property. To clear form errors, - use the clearErrors() method. + In addition to the <Form> component, Inertia also provides a useForm helper for + when you need programmatic control over your form's data and submission behavior:

+ import { useForm } from '@inertiajs/vue3' - // Clear errors for specific fields... - form.clearErrors('field', 'anotherfield') + const form = useForm({ + email: null, + password: null, + remember: false, + }) + + + `, }, { name: 'React', - language: 'js', + language: 'jsx', code: dedent` - const { clearErrors } = useForm({ ... }) + import { useForm } from '@inertiajs/react' - // Clear all errors... - clearErrors() + const { data, setData, post, processing, errors } = useForm({ + email: '', + password: '', + remember: false, + }) - // Clear errors for specific fields... - clearErrors('field', 'anotherfield') - `, - }, - { - name: 'Svelte', - language: 'js', - code: dedent` - // Clear all errors... - $form.clearErrors() + function submit(e) { + e.preventDefault() + post('/login') + } - // Clear errors for specific fields... - $form.clearErrors('field', 'anotherfield') + return ( +
+ setData('email', e.target.value)} /> + {errors.email &&
{errors.email}
} + setData('password', e.target.value)} /> + {errors.password &&
{errors.password}
} + setData('remember', e.target.checked)} /> Remember Me + +
+ ) `, }, - ]} - /> -

- If you're using client-side input validation libraries or do client-side validation manually, you can set your - own errors on the form using the setErrors() method. -

- + import { useForm } from '@inertiajs/svelte' - // Set multiple errors at once... - form.setError({ - foo: 'Your error message for the foo field.', - bar: 'Some other error for the bar field.' - }); - `, - }, - { - name: 'React', - language: 'js', - code: dedent` - const { setError } = useForm({ ... }) + const form = useForm({ + email: null, + password: null, + remember: false, + }) - // Set a single error... - setError('field', 'Your error message.'); + function submit() { + $form.post('/login') + } + - // Set multiple errors at once... - setError({ - foo: 'Your error message for the foo field.', - bar: 'Some other error for the bar field.' - }); +
+ + {#if $form.errors.email} +
{$form.errors.email}
+ {/if} + + {#if $form.errors.password} +
{$form.errors.password}
+ {/if} + Remember Me + +
`, }, { - name: 'Svelte', - language: 'js', + name: 'Svelte 5', + language: 'jsx', code: dedent` - // Set a single error - $form.setError('field', 'Your error message.'); + + +
+ + {#if $form.errors.email} +
{$form.errors.email}
+ {/if} + + {#if $form.errors.password} +
{$form.errors.password}
+ {/if} + Remember Me + +
`, }, ]} /> - - Unlike an actual form submission, the page's props remain unchanged when manually setting errors on a form - instance. -

- When a form has been successfully submitted, the wasSuccessful property will be true. - In addition to this, forms have a recentlySuccessful property, which will be set to{' '} - true for two seconds after a successful form submission. This property can be utilized to show - temporary success messages. -

-

- To reset the form's values back to their default values, you can use the reset() method. + To submit the form, you may use the get, post, put, patch{' '} + and delete methods.

- Sometimes, you may want to restore your form fields to their default values and clear any validation errors at{' '} - the same time. Instead of calling reset() and clearErrors() separately, you can use the{' '} - resetAndClearErrors() method, which combines both actions into a single call. + The submit methods support all of the typical visit options, such as{' '} + preserveState, preserveScroll, and event callbacks, which can be helpful for + performing tasks on successful form submissions. For example, you might use the onSuccess{' '}callback + to reset inputs to their original state.

form.reset('password'), + }) `, }, { name: 'React', language: 'js', code: dedent` - const { resetAndClearErrors } = useForm({ ... }) - - // Reset the form and clear all errors... - resetAndClearErrors() + const { post, reset } = useForm({ ... }) - // Reset specific fields and clear their errors... - resetAndClearErrors('field', 'anotherfield') + post('/profile', { + preserveScroll: true, + onSuccess: () => reset('password'), + }) `, }, { name: 'Svelte', language: 'js', code: dedent` - // Reset the form and clear all errors... - $form.resetAndClearErrors() - - // Reset specific fields and clear their errors... - $form.resetAndClearErrors('field', 'anotherfield') + $form.post('/profile', { + preserveScroll: true, + onSuccess: () => $form.reset('password'), + }) `, }, ]} />

- If your form's default values become outdated, you can use the defaults() method to update them. - Then, the form will be reset to the correct values the next time the reset() method is invoked. + If you need to modify the form data before it's sent to the server, you can do so via the{' '} + transform() method.

({ + ...data, + remember: data.remember ? 'on' : '', + })) + .post('/login') `, }, { name: 'React', language: 'js', code: dedent` - const { setDefaults } = useForm({ ... }) - - // Set the form's current values as the new defaults... - setDefaults() - - // Update the default value of a single field... - setDefaults('email', 'updated-default@example.com') + const { transform } = useForm({ ... }) - // Update the default value of multiple fields... - setDefaults({ - name: 'Updated Example', - email: 'updated-default@example.com', - }) + transform((data) => ({ + ...data, + remember: data.remember ? 'on' : '', + })) `, }, { name: 'Svelte', language: 'js', code: dedent` - // Set the form's current values as the new defaults... - $form.defaults() - - // Update the default value of a single field... - $form.defaults('email', 'updated-default@example.com') - - // Change the default value of multiple fields... - $form.defaults({ - name: 'Updated Example', - email: 'updated-default@example.com', - }) + $form + .transform((data) => ({ + ...data, + remember: data.remember ? 'on' : '', + })) + .post('/login') `, }, ]} />

- To determine if a form has any changes, you may use the isDirty property. + You can use the processing property to track if a form is currently being submitted. This can be + helpful for preventing double form submissions by disabling the submit button.

There are unsaved form changes. + `, }, { name: 'React', language: 'jsx', code: dedent` - const { isDirty } = useForm({ ... }) + const { processing } = useForm({ ... }) - {isDirty &&
There are unsaved form changes.
} + `, }, { name: 'Svelte', - language: 'html', + language: 'jsx', code: dedent` - {#if $form.isDirty} -
There are unsaved form changes.
- {/if} + `, }, ]} />

- To cancel a form submission, use the cancel() method. + If your form is uploading files, the current progress event is available via the progress property, + allowing you to easily display the upload progress.

+ {{ form.progress.percentage }}% + `, }, { name: 'React', - language: 'js', + language: 'jsx', code: dedent` - const { cancel } = useForm({ ... }) + const { progress } = useForm({ ... }) - cancel() + {progress && ( + + {progress.percentage}% + + )} `, }, { name: 'Svelte', - language: 'js', + language: 'jsx', code: dedent` - $form.cancel() + {#if $form.progress} + + {$form.progress.percentage}% + + {/if} `, }, ]} />

- To instruct Inertia to store a form's data and errors in history state, you can - provide a unique form key as the first argument when instantiating your form. + If there are form validation errors, they are available via the errors property. When building + Laravel powered Inertia applications, form errors will automatically be populated when your application throws + instances of ValidationException, such as when using {'$request->validate()'}.

{{ form.errors.email }} `, }, { name: 'React', - language: 'js', + language: 'jsx', code: dedent` - import { useForm } from '@inertiajs/react' + const { errors } = useForm({ ... }) - const form = useForm('CreateUser', data) - const form = useForm(\`EditUser:\${user.id}\`, data) + {errors.email &&
{errors.email}
} `, }, { name: 'Svelte', - language: 'js', + language: 'jsx', code: dedent` - import { useForm } from '@inertiajs/svelte' - - const form = useForm('CreateUser', data) - const form = useForm(\`EditUser:\${user.id}\`, data) + {#if $form.errors.email} +
{$form.errors.email}
+ {/if} `, }, ]} /> -

Wayfinder

-

- Requires Inertia >= v2.0.6 -

+ + For a more thorough discussion of form validation and errors, please consult the{' '} + validation documentation. +

- When using Wayfinder in conjunction with the form helper, you - can simply pass the resulting object directly to the form.submit method. The form helper will infer - the HTTP method and URL from the Wayfinder object: + To determine if a form has any errors, you may use the hasErrors property. To clear form errors, + use the clearErrors() method.

-

Form component

- As an alternative to the useForm helper, Inertia provides a <Form> component that - offers a declarative approach to form handling. At its simplest, the component behaves much like a classic HTML - form, but with all the benefits of Inertia's SPA-like navigation. While useForm() gives you programmatic - control over form data and submission logic, the <Form> component is ideal when you prefer a - more HTML-like, declarative approach. + If you're using client-side input validation libraries or do client-side validation manually, you can set your + own errors on the form using the setErrors() method.

- - - - + // Set a single error... + form.setError('field', 'Your error message.'); + + // Set multiple errors at once... + form.setError({ + foo: 'Your error message for the foo field.', + bar: 'Some other error for the bar field.' + }); `, }, { name: 'React', - language: 'jsx', + language: 'js', code: dedent` -
- - - -
+ const { setError } = useForm({ ... }) + + // Set a single error... + setError('field', 'Your error message.'); + + // Set multiple errors at once... + setError({ + foo: 'Your error message for the foo field.', + bar: 'Some other error for the bar field.' + }); `, }, { name: 'Svelte', - language: 'html', + language: 'js', code: dedent` -
- - - -
+ // Set a single error + $form.setError('field', 'Your error message.'); + + // Set multiple errors at once + $form.setError({ + foo: 'Your error message for the foo field.', + bar: 'Some other error for the bar field.' + }); `, }, ]} /> + + Unlike an actual form submission, the page's props remain unchanged when manually setting errors on a form + instance. +

- The component also supports advanced use cases, including nested data structures, file uploads, and dotted key notation: + When a form has been successfully submitted, the wasSuccessful property will be true. + In addition to this, forms have a recentlySuccessful property, which will be set to{' '} + true for two seconds after a successful form submission. This property can be utilized to show + temporary success messages. +

+

+ To reset the form's values back to their default values, you can use the reset() method.

- - - - - - + // Reset the form... + form.reset() + + // Reset specific fields... + form.reset('field', 'anotherfield') `, }, { name: 'React', - language: 'jsx', + language: 'js', code: dedent` -
- - - - - -
+ const { reset } = useForm({ ... }) + + // Reset the form... + reset() + + // Reset specific fields... + reset('field', 'anotherfield') `, }, { name: 'Svelte', - language: 'html', + language: 'js', code: dedent` -
- - - - - -
+ // Reset the form... + $form.reset() + + // Reset specific fields... + $form.reset('field', 'anotherfield') `, }, ]} />

- You can pass a transform prop to modify the form data before submission. This is useful for - injecting additional fields or transforming existing data, although hidden inputs work too: + Sometimes, you may want to restore your form fields to their default values and clear any validation errors at + the same time. Instead of calling reset() and clearErrors() separately, you can use the{' '} + resetAndClearErrors() method, which combines both actions into a single call.

- - - + // Reset the form and clear all errors... + form.resetAndClearErrors() + + // Reset specific fields and clear their errors... + form.resetAndClearErrors('field', 'anotherfield') `, }, { name: 'React', - language: 'jsx', + language: 'js', code: dedent` -
({ ...data, user_id: 123 })} - > - - -
+ const { resetAndClearErrors } = useForm({ ... }) + + // Reset the form and clear all errors... + resetAndClearErrors() + + // Reset specific fields and clear their errors... + resetAndClearErrors('field', 'anotherfield') `, }, { name: 'Svelte', - language: 'html', + language: 'js', code: dedent` -
({ ...data, user_id: 123 })} - > - - -
+ // Reset the form and clear all errors... + $form.resetAndClearErrors() + + // Reset specific fields and clear their errors... + $form.resetAndClearErrors('field', 'anotherfield') `, }, ]} /> -

Slot props

- Just like the useForm() helper, the <Form> component exposes reactive state - and helper methods through its default slot: + If your form's default values become outdated, you can use the defaults() method to update them. + Then, the form will be reset to the correct values the next time the reset() method is invoked.

- -
{{ errors.name }}
+ // Set the form's current values as the new defaults... + form.defaults() - + // Update the default value of a single field... + form.defaults('email', 'updated-default@example.com') -
User created successfully!
- + // Update the default value of multiple fields... + form.defaults({ + name: 'Updated Example', + email: 'updated-default@example.com', + }) `, }, { name: 'React', - language: 'jsx', + language: 'js', code: dedent` -
- {({ - errors, - hasErrors, - processing, - progress, - wasSuccessful, - recentlySuccessful, - setError, - clearErrors, - resetAndClearErrors, - isDirty, - reset, - submit, - }) => ( - <> - - {errors.name &&
{errors.name}
} - - + const { setDefaults } = useForm({ ... }) - {wasSuccessful &&
User created successfully!
} - - )} -
- `, - }, - { - name: 'Svelte 4', - language: 'html', - code: dedent` -
- - {#if errors.name} -
{errors.name}
- {/if} + // Set the form's current values as the new defaults... + setDefaults() - + // Update the default value of a single field... + setDefaults('email', 'updated-default@example.com') - {#if wasSuccessful} -
User created successfully!
- {/if} -
+ // Update the default value of multiple fields... + setDefaults({ + name: 'Updated Example', + email: 'updated-default@example.com', + }) `, }, - { - name: 'Svelte 5', - language: 'html', + { + name: 'Svelte', + language: 'js', code: dedent` -
- {#snippet children({ - errors, - hasErrors, - processing, - progress, - wasSuccessful, - recentlySuccessful, - setError, - clearErrors, - resetAndClearErrors, - isDirty, - reset, - submit, - })} - - {#if errors.name} -
{errors.name}
- {/if} + // Set the form's current values as the new defaults... + $form.defaults() - + // Update the default value of a single field... + $form.defaults('email', 'updated-default@example.com') - {#if wasSuccessful} -
User created successfully!
- {/if} - {/snippet} -
+ // Change the default value of multiple fields... + $form.defaults({ + name: 'Updated Example', + email: 'updated-default@example.com', + }) `, }, ]} />

- The errors object uses dotted notation for nested fields, allowing you to display validation - messages for complex form structures: + To determine if a form has any changes, you may use the isDirty property.

- -
{{ errors['user.name'] }}
- +
There are unsaved form changes.
`, }, { name: 'React', language: 'jsx', code: dedent` -
- {({ errors }) => ( - <> - - {errors['user.name'] &&
{errors['user.name']}
} - - )} -
- `, - }, - { - name: 'Svelte 4', - language: 'html', - code: dedent` -
- - {#if errors['user.name']} -
{errors['user.name']}
- {/if} -
+ const { isDirty } = useForm({ ... }) + + {isDirty &&
There are unsaved form changes.
} `, }, { - name: 'Svelte 5', + name: 'Svelte', language: 'html', code: dedent` -
- {#snippet children({ errors })} - - {#if errors['user.name']} -
{errors['user.name']}
- {/if} - {/snippet} -
+ {#if $form.isDirty} +
There are unsaved form changes.
+ {/if} `, }, ]} /> -

Props and options

- In addition to action and method, the <Form> component accepts - several props. Many of them are identical to the options available in Inertia's{' '} - visit options: + To cancel a form submission, use the cancel() method.

- - - + form.cancel() `, }, { name: 'React', - language: 'jsx', + language: 'js', code: dedent` -
({ ...data, timestamp: Date.now() })} - options={{ - preserveScroll: true, - preserveState: true, - preserveUrl: true, - replace: true, - only: ['users', 'flash'], - except: ['secret'], - reset: ['page'], - }} - > - - -
+ const { cancel } = useForm({ ... }) + + cancel() `, }, { name: 'Svelte', - language: 'html', + language: 'js', code: dedent` -
({ ...data, timestamp: Date.now() })} - options={{ - preserveScroll: true, - preserveState: true, - preserveUrl: true, - replace: true, - only: ['users', 'flash'], - except: ['secret'], - reset: ['page'], - }} - > - - -
+ $form.cancel() `, }, ]} />

- Some props are intentionally grouped under options instead of being top-level to avoid confusion. - For example, only, except, and reset relate to partial reloads, - not partial submissions. The general rule: top-level props are for the form submission itself, while{' '} - options control how Inertia handles the subsequent visit. -

-

Events

-

- The <Form> component emits all the standard visit events for form - submissions, plus a cancelToken event for handling form cancellation: + To instruct Inertia to store a form's data and errors in history state, you can + provide a unique form key as the first argument when instantiating your form.

- - - + import { useForm } from '@inertiajs/vue3' + + const form = useForm('CreateUser', data) + const form = useForm(\`EditUser:\${user.id}\`, data) `, }, { name: 'React', - language: 'jsx', - code: dedent` -
- - -
- `, - }, - { - name: 'Svelte 4', - language: 'html', + language: 'js', code: dedent` -
- - -
+ import { useForm } from '@inertiajs/react' + + const form = useForm('CreateUser', data) + const form = useForm(\`EditUser:\${user.id}\`, data) `, }, { - name: 'Svelte 5', - language: 'html', - code: dedent` -
- - -
+ name: 'Svelte', + language: 'js', + code: dedent` + import { useForm } from '@inertiajs/svelte' + + const form = useForm('CreateUser', data) + const form = useForm(\`EditUser:\${user.id}\`, data) `, }, ]} /> -

Dotted key notation

+

Wayfinder

- The <Form> component supports dotted key notation for creating nested objects from flat - input names. This provides a convenient way to structure form data. + Requires Inertia >= v2.0.6 +

+

+ When using Wayfinder in conjunction with the form helper, you + can simply pass the resulting object directly to the form.submit method. The form helper will infer + the HTTP method and URL from the Wayfinder object:

- - - - - + import { useForm } from '@inertiajs/vue3' + import { store } from 'App/Http/Controllers/UserController' + + const form = useForm({ + name: 'John Doe', + email: 'john.doe@example.com', + }) + + form.submit(store()) `, }, { name: 'React', - language: 'jsx', + language: 'js', code: dedent` -
- - - - -
+ import { useForm } from '@inertiajs/react' + import { store } from 'App/Http/Controllers/UserController' + + const form = useForm({ + name: 'John Doe', + email: 'john.doe@example.com', + }) + + form.submit(store()) `, }, { name: 'Svelte', - language: 'html', + language: 'js', code: dedent` -
- - - - -
+ import { useForm } from '@inertiajs/svelte' + import { store } from 'App/Http/Controllers/UserController' + + const form = useForm({ + name: 'John Doe', + email: 'john.doe@example.com', + }) + + form.submit(store()) `, }, ]} /> +

Server-side responses

- The above example would generate the following data structure: + When using Inertia, you don't typically inspect form responses client-side like you would with traditional XHR/fetch + requests. Instead, your server-side route or controller issues a redirect response after + processing the form, often redirecting to a success page.

User::all(), + ]); + } + + public function store(Request $request) + { + User::create($request->validate([ + 'first_name' => ['required', 'max:50'], + 'last_name' => ['required', 'max:50'], + 'email' => ['required', 'max:50', 'email'], + ])); + + return to_route('users.index'); + } } `, }, ]} />

- If you need literal dots in your field names (not as nested object separators), you can escape them using - backslashes: + This redirect-based approach works with all form submission methods: the <Form> component, + useForm helper, and manual router submissions. It makes handling Inertia forms feel very similar to + classic server-side form submissions. +

+

Server-side validation

+

+ Both the <Form> component and useForm helper automatically handle server-side + validation errors. When your server returns validation errors, they're automatically available in the errors{' '} + object without any additional configuration. +

+

+ Unlike traditional XHR/fetch requests where you'd check for a 422 status code, Inertia handles + validation errors as part of its redirect-based flow, just like classic server-side form submissions, but without + the full page reload. +

+

+ For a complete guide on validation error handling, including error bags and advanced scenarios, see the{' '} + validation documentation. +

+

Manual form submissions

+

+ It's also possible to submit forms manually using Inertia's router methods directly, without using + the <Form> component or useForm helper:

- - - - + + + `, }, { name: 'React', language: 'jsx', code: dedent` -
- - - -
+ import { useState } from 'react' + import { router } from '@inertiajs/react' + + export default function Edit() { + const [values, setValues] = useState({ + first_name: "", + last_name: "", + email: "", + }) + + function handleChange(e) { + const key = e.target.id; + const value = e.target.value + setValues(values => ({ + ...values, + [key]: value, + })) + } + + function handleSubmit(e) { + e.preventDefault() + router.post('/users', values) + } + + return ( +
+ + + + + + + +
+ ) + } `, }, { - name: 'Svelte', + name: 'Svelte 4', language: 'html', code: dedent` -
- - - -
+ + +
+ + + + + + + + + + +
`, }, - ]} - /> -

- This would result in: -

- + import { router } from '@inertiajs/svelte' + + let values = { + first_name: null, + last_name: null, + email: null, } - } + + function submit(e) { + e.preventDefault() + router.post('/users', values) + } + + +
+ + + + + + + + + + +
`, }, ]} @@ -1670,18 +1668,19 @@ export default function () {

File uploads

When making requests or form submissions that include files, Inertia will automatically convert the request data - into a FormData object. + into a FormData object. This works with the <Form> component, useForm{' '} + helper, and manual router submissions.

- For a more thorough discussion of file uploads, please consult the{' '} + For more information on file uploads, including progress tracking, see the{' '} file uploads documentation.

XHR / fetch submissions

- Using Inertia to submit forms works great for the vast majority of situations; however, in the event that you - need more control over the form submission, you're free to make plain XHR or fetch requests instead + Using Inertia to submit forms works great for the vast majority of situations. However, in the event that you + need more control over the form submission, you're free to make plain XHR or fetch requests instead, using the library of your choice.

) -} +} \ No newline at end of file From 8c1a80e909b0c04fbdefcb9414b7d0b0cd07e647 Mon Sep 17 00:00:00 2001 From: Pascal Baljet Date: Tue, 12 Aug 2025 12:03:31 +0200 Subject: [PATCH 5/5] wip --- resources/js/Pages/forms.jsx | 118 +++++++++++++++++++++++++++++++---- 1 file changed, 105 insertions(+), 13 deletions(-) diff --git a/resources/js/Pages/forms.jsx b/resources/js/Pages/forms.jsx index 232052cf..9ef8aa61 100644 --- a/resources/js/Pages/forms.jsx +++ b/resources/js/Pages/forms.jsx @@ -18,9 +18,13 @@ export default function () { return ( <>

Forms

+

+ Inertia provides two primary ways to build forms: the <Form> component and the useForm helper. + Both integrate with your server-side framework's validation and handle form submissions without full page reloads. +

Form component

- Inertia provides a <Form> component that behaves much like a classic HTML form, but uses + Inertia provides a <Form> component that behaves much like a classic HTML form, but uses Inertia under the hood to avoid full page reloads. This is the simplest way to get started with forms in Inertia:

Slot props

- The <Form> component exposes reactive state and helper methods through its default slot, + The <Form> component exposes reactive state and helper methods through its default slot, giving you access to form processing state, errors, and utility functions:

+

Programmatic access

+

+ You can access the form's methods programmatically using refs. This provides an alternative to the{' '} + slot props approach when you need to trigger form actions from outside the form: +

+ + import { ref } from 'vue' + import { Form } from '@inertiajs/vue3' + + const formRef = ref() + + const handleSubmit = () => { + formRef.value.submit() + } + + + + `, + }, + { + name: 'React', + language: 'jsx', + code: dedent` + import { useRef } from 'react' + import { Form } from '@inertiajs/react' + + export default function CreateUser() { + const formRef = useRef() + + const handleSubmit = () => { + formRef.current.submit() + } + + return ( + <> +
+ + +
+ + + + ) + } + `, + }, + { + name: 'Svelte', + language: 'html', + code: dedent` + + +
+ + +
+ + + `, + }, + ]} + /> +

+ In React and Vue, refs provide access to all form methods and reactive state. In Svelte, refs expose only + methods, so reactive state like isDirty and errors should be accessed via{' '} + slot props instead. +

Form helper

- In addition to the <Form> component, Inertia also provides a useForm helper for + In addition to the <Form> component, Inertia also provides a useForm helper for when you need programmatic control over your form's data and submission behavior:

- Sometimes, you may want to restore your form fields to their default values and clear any validation errors at + Sometimes, you may want to restore your form fields to their default values and clear any validation errors at the same time. Instead of calling reset() and clearErrors() separately, you can use the{' '} resetAndClearErrors() method, which combines both actions into a single call.

@@ -1463,8 +1555,8 @@ export default function () { />

Server-side responses

- When using Inertia, you don't typically inspect form responses client-side like you would with traditional XHR/fetch - requests. Instead, your server-side route or controller issues a redirect response after + When using Inertia, you don't typically inspect form responses client-side like you would with traditional XHR/fetch + requests. Instead, your server-side route or controller issues a redirect response after processing the form, often redirecting to a success page.

- This redirect-based approach works with all form submission methods: the <Form> component, - useForm helper, and manual router submissions. It makes handling Inertia forms feel very similar to + This redirect-based approach works with all form submission methods: the <Form> component, + useForm helper, and manual router submissions. It makes handling Inertia forms feel very similar to classic server-side form submissions.

Server-side validation

- Both the <Form> component and useForm helper automatically handle server-side + Both the <Form> component and useForm helper automatically handle server-side validation errors. When your server returns validation errors, they're automatically available in the errors{' '} object without any additional configuration.

- Unlike traditional XHR/fetch requests where you'd check for a 422 status code, Inertia handles - validation errors as part of its redirect-based flow, just like classic server-side form submissions, but without + Unlike traditional XHR/fetch requests where you'd check for a 422 status code, Inertia handles + validation errors as part of its redirect-based flow, just like classic server-side form submissions, but without the full page reload.

@@ -1519,7 +1611,7 @@ export default function () {

Manual form submissions

- It's also possible to submit forms manually using Inertia's router methods directly, without using + It's also possible to submit forms manually using Inertia's router methods directly, without using the <Form> component or useForm helper:

File uploads

When making requests or form submissions that include files, Inertia will automatically convert the request data - into a FormData object. This works with the <Form> component, useForm{' '} + into a FormData object. This works with the <Form> component, useForm{' '} helper, and manual router submissions.