Skip to main content

Form Customization

Four levels of customization: field metadata via zaf, custom layout, full control, and custom submit buttons.

Field Metadata (zaf)

Use zaf to add labels, descriptions, custom components, or hide fields — without changing layout code.

import { zaf } from '@repo/form'

const schema = z.object({
role: zaf(z.enum(['admin', 'user']), {
label: 'User Role',
description: 'Select permission level',
}),
internal: zaf(z.string(), { skip: true }),
rating: zaf(z.number(), { component: CustomRating, props: { max: 5 } }),
})

See zaf docs for all options and custom component examples.

Custom Layout

Control field placement while keeping automatic field rendering.

Remote Forms

<TypedForm.Remote form={createUserForm} schema={userSchema}>
{#snippet children({ fields })}
<div class="grid grid-cols-2 gap-4">
<TypedForm.RemoteField field={fields.name} />
<TypedForm.RemoteField field={fields.email} />
</div>
{/snippet}
</TypedForm.Remote>

Client Forms

<TypedForm.Client bind:value {schema} onsubmit={handleSubmit}>
{#snippet fields({ fields, value })}
<div class="grid grid-cols-2 gap-4">
<TypedForm.Field field={fields.name} bind:value={value.name} />
<TypedForm.Field field={fields.email} bind:value={value.email} />
</div>
{/snippet}
</TypedForm.Client>

Full Control

Manual input rendering for complete customization.

Remote Forms

<TypedForm.Remote form={createUserForm} schema={userSchema}>
<TypedForm.RemoteControl formField={createUserForm.fields.name}>
{#snippet children({ formField })}
<TypedForm.TextInput {...formField.as('text')} />
{/snippet}
</TypedForm.RemoteControl>
</TypedForm.Remote>

Client Forms

<TypedForm.Client bind:value {schema} onsubmit={handleSubmit}>
{#snippet children()}
<TypedForm.Control name="name">
{#snippet children()}
<TypedForm.TextInput name="name" bind:value={value.name} />
{/snippet}
</TypedForm.Control>
{/snippet}
</TypedForm.Client>

Custom Submit Button

<TypedForm.Remote form={createUserForm} schema={userSchema}>
{#snippet button({ submitting })}
<Button type="submit" disabled={submitting}>
{submitting ? 'Saving...' : 'Save'}
</Button>
{/snippet}
</TypedForm.Remote>