MonoStack
Guides

Form Customization

Three levels of customization: custom layout with typed fields, full control, and custom submit buttons.

Custom Layout

Control field placement with typed fields. Props are typed based on the field type.

Remote Forms

<TypedForm.Remote form={createUserForm} schema={userSchema}>
  {#snippet children({ fields })}
    <div class="grid grid-cols-2 gap-4">
      <!-- Props typed to TextField (placeholder, etc.) -->
      <TypedForm.RemoteField field={fields.name} placeholder="Enter name" />
      <TypedForm.RemoteField field={fields.email} placeholder="Enter email" />
    </div>

    <!-- Override component with input prop (props typed to that component) -->
    <TypedForm.RemoteField field={fields.bio} input={TypedForm.TextareaInput} rows={5} />

    <!-- Custom component -->
    <TypedForm.RemoteField field={fields.rating} input={CustomRating} max={5} />
  {/snippet}
</TypedForm.Remote>

Client Forms

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

    <!-- Override component with input prop -->
    <TypedForm.Field
      field={fields.bio}
      bind:value={value.bio}
      input={TypedForm.TextareaInput}
      rows={5}
    />
  {/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>

On this page