Manual Usage
Most forms use PHP form classes and the generated <Form> component. For layout and presentation changes, start with Slots and Children, Styling, Customizing Presenters, or Custom Fields. Use this page for the remaining cases: placing package controls yourself, or rendering standalone controls outside an Inertia Forms form.
Manual rendering leaves the surrounding markup, layout, and any replaced behavior in your application.
There are two options:
- Manual form rendering: keep the serialized PHP form config, call
useForm, provide form context, and passform.getField(...)into package fields. - Standalone components: import package fields directly and bind values with Vue
v-modelor React props. No PHP form config or package form provider is involved.
Import Paths
| Surface | Vue | React |
|---|---|---|
Form shell, useForm, FieldRenderer, shared helpers, and types | @inertiaui/form-vue | @inertiaui/form-react |
| Field components | @inertiaui/form-vue/components | @inertiaui/form-react/components |
| RichText | @inertiaui/form-vue/richtext | @inertiaui/form-react/richtext |
Use the installation guide for runtime setup and styles. The source and generated TypeScript declarations for your installed version are the detailed reference.
Manual Form Rendering
You may render fields manually while keeping the backend form definition, validation, submission, and conditional visibility authoritative. Provide form context, then pass serialized field payloads from form.getField(...) to the components.
<script setup>
import { provide } from 'vue'
import { FormContextKey, useForm } from '@inertiaui/form-vue'
import { TextInput } from '@inertiaui/form-vue/components'
const props = defineProps({ form: Object })
const form = useForm(props.form)
provide(FormContextKey, {
formId: form.formId,
data: form.data,
rootData: form.data,
errors: form.errors,
processing: form.processing,
setData: form.setData,
validate: form.validate,
})
</script>
<template>
<form @submit.prevent="form.submit()">
<TextInput v-bind="form.getField('name')" />
<TextInput v-bind="form.getField('email')" />
<button type="submit" :disabled="form.processing.value">
Save
</button>
</form>
</template>import { FormContext, useForm } from '@inertiaui/form-react'
import { TextInput } from '@inertiaui/form-react/components'
export default function ManualProfileForm({ form: config }) {
const form = useForm(config)
const submit = (event) => {
event.preventDefault()
form.submit({ formElement: event.currentTarget })
}
return (
<FormContext.Provider
value={{
formId: form.formId,
data: form.data,
rootData: form.data,
errors: form.errors,
rootErrors: form.errors,
processing: form.processing,
setData: form.setData,
validate: form.validate,
}}
>
<form onSubmit={submit}>
<TextInput {...form.getField('name')} />
<TextInput {...form.getField('email')} />
<button type="submit" disabled={form.processing}>
Save
</button>
</form>
</FormContext.Provider>
)
}useForm gives you the form data, errors, processing state, dirty tracking, validation, submission, and getField(name) helper. Vue exposes some values as refs or computed refs. React returns plain values.
Submitter Data In Manual Forms
The generated <Form> captures the clicked submit button automatically. Pass the native submitter from manual wrappers with named submit buttons.
const submit = (event) => {
form.submit({
submitter: event.submitter instanceof HTMLElement ? event.submitter : null,
})
}const submit = (event) => {
event.preventDefault()
form.submit({
formElement: event.currentTarget,
submitter: event.nativeEvent.submitter instanceof HTMLElement
? event.nativeEvent.submitter
: null,
})
}Only an enabled submit button or submit input with a name contributes submitter data.
Standalone Components
You may use standalone components for dialogs, filters, toolbars, local settings, or other UI that needs package controls without a generated PHP form payload. This uses the shipped presenters as-is. Use Customizing Presenters to copy or replace presenter markup. Standalone bindings win over inherited form context.
<script setup>
import { ref } from 'vue'
import { TextInput, Toggle } from '@inertiaui/form-vue/components'
const title = ref('Launch notes')
const published = ref(true)
</script>
<template>
<TextInput v-model="title" label="Title" name="title" />
<Toggle v-model="published" label="Published" />
</template>import { useState } from 'react'
import { TextInput, Toggle } from '@inertiaui/form-react/components'
export default function ArticleControls() {
const [title, setTitle] = useState('Launch notes')
const [published, setPublished] = useState(true)
return (
<>
<TextInput value={title} onValueChange={setTitle} label="Title" name="title" />
<Toggle checked={published} onCheckedChange={setPublished} label="Published" />
</>
)
}Standalone name is optional. You may provide it for native form names or hidden inputs in a non-package form. Omit it for client-only controls.
Native Attributes And Events
Direct components forward common data-*, aria-*, autocomplete, keyboard, focus, blur, and change props to the stable interactive surface.
<TextInput
v-model="title"
label="Title"
data-testid="article-title"
autocomplete="off"
@blur="trackTitleBlur"
/><TextInput
value={title}
onValueChange={setTitle}
label="Title"
data-testid="article-title"
autoComplete="off"
onBlur={trackTitleBlur}
/>Composite controls such as listboxes, popovers, uploads, editors, and collections own their internal ARIA and DOM structure. Use their documented props, classes, and partClasses instead of relying on internal nodes.
Standalone Uploads And Remote Controls
Most standalone inputs only need a value binding and display props. Remote, editor, upload, and composer controls need explicit endpoint or upload configuration because standalone mode does not inherit PHP form config:
RichTextis imported from therichtextsubpath. Image uploads need an explicitimageUploadsconfig.FileUploadneeds explicit temporary, chunked, or direct-to-storage upload props when files are uploaded before final submit.Composerwrites plain text by default. Attachments require the same upload decisions as file uploads.Comboboxmay use inlineoptions. Remote search, record creation, and selected-value lookup need explicitsource,selectedSource, orcreateprops.
Rendering Serialized Fields
You may use FieldRenderer inside a package <Form> or manual FormContext provider to let the registry choose the presenter for one serialized field. Custom presenters and custom field registration are documented on Customizing Presenters and Custom Fields.