---
title: Form
description: Styled Formisch form that provides its store to Moraine form fields.
sidebar:
  order: 1
search:
  tags: [Formisch, validation, submit, store]
---

# Form

> Styled Formisch form that provides its store to Moraine form fields.

## Import

Create the Formisch store with a Valibot schema, then pass it to `Form`. Moraine fields and
controls bind to the store automatically through `FormField.name`.

```tsx
import { createForm, Form, Input, Switch } from 'moraine'

export function NoticationForm() {
  const form = createForm({
    schema,
    initialInput: { email: '', enabled: false },
  })
  const save = (output) => {}

  return (
    <Form of={form} onSubmit={(output) => save(output)}>
      <FormField name="email" label="Email">
        <Input />
      </FormField>
      <FormField name="enabled" label="Enable notifications">
        <Switch />
      </FormField>
    </Form>
  )
}
```

For field arrays or custom rendering, import `Field`, `FieldArray`, `useField`, and Formisch
methods directly from `@formisch/solid` and use the same store.

## Examples

### Workspace Provisioning

Create a new workspace with owner identity, default role, and rollout target.

```tsx
function WorkspaceProvisioning() {
  const [submittedWorkspace, setSubmittedWorkspace] = createSignal<string>()
  const form = createForm({
    schema: WorkspaceSchema,
    initialInput: {
      workspaceName: '',
      ownerEmail: '',
      role: 'developer',
      environment: 'staging',
      enableAudit: true,
    },
  })

  return (
    <Form
      of={form}
      onSubmit={(output) => setSubmittedWorkspace(`Created ${output.workspaceName}.`)}
      class="mx-auto max-w-2xl w-full space-y-4"
    >
      <FormField<typeof WorkspaceSchema> name="workspaceName" label="Workspace Name" required>
        <Input placeholder="acme-platform" />
      </FormField>

      <FormField<typeof WorkspaceSchema> name="ownerEmail" label="Owner Email" required>
        <Input type="email" placeholder="owner@acme.dev" />
      </FormField>

      <FormField<typeof WorkspaceSchema> name="role" label="Default Team Role" required>
        <Select
          options={[
            { label: 'Developer', value: 'developer' },
            { label: 'Designer', value: 'designer' },
            { label: 'Manager', value: 'manager' },
          ]}
          placeholder="Select role"
        />
      </FormField>

      <FormField<typeof WorkspaceSchema>
        name="environment"
        label="Initial Deployment Target"
        required
      >
        <RadioGroup
          items={[
            { value: 'staging', label: 'Staging', description: 'Pre-production verification' },
            { value: 'production', label: 'Production', description: 'Public traffic rollout' },
          ]}
          variant="table"
        />
      </FormField>

      <FormField<typeof WorkspaceSchema>
        name="enableAudit"
        label="Audit Logging"
        description="Enable immutable audit trail for permissions and deploy actions."
      >
        <Switch checkedIcon="i-lucide-shield-check" uncheckedIcon="i-lucide-shield" />
      </FormField>

      <Button type="submit">Create Workspace</Button>
      <Show when={submittedWorkspace()}>
        {(message) => <p class="text-success text-sm">{message()}</p>}
      </Show>
    </Form>
  )
}
```

### Release Readiness Checklist

Validate release metadata, rollout channels, and approval gate with a Formisch schema.

```tsx
function ReleaseReadinessChecklist() {
  const [approvedRelease, setApprovedRelease] = createSignal<string>()
  const form = createForm({
    schema: ReleaseReadinessSchema,
    initialInput: {
      releaseVersion: '',
      channels: [],
      approvalLevel: 'peer',
      rolloutConfirmed: false,
      notes: '',
    },
  })
  return (
    <Form
      of={form}
      onSubmit={(output) => setApprovedRelease(`${output.releaseVersion} is ready for rollout.`)}
      class="mx-auto max-w-2xl w-full space-y-4"
    >
      <FormField<typeof ReleaseReadinessSchema>
        name="releaseVersion"
        label="Release Version"
        required
      >
        <Input placeholder="v2.14.0" />
      </FormField>

      <FormField<typeof ReleaseReadinessSchema> name="channels" label="Rollout Channels" required>
        <CheckboxGroup
          items={[
            {
              value: 'alpha',
              label: 'Alpha',
              description: 'Internal team first',
            },
            {
              value: 'beta',
              label: 'Beta',
              description: 'Limited external users',
            },
            {
              value: 'stable',
              label: 'Stable',
              description: 'Full production release',
            },
          ]}
          variant="table"
        />
      </FormField>

      <FormField<typeof ReleaseReadinessSchema> name="approvalLevel" label="Approval Gate" required>
        <RadioGroup
          items={[
            {
              value: 'peer',
              label: 'Peer Review',
              description: 'One teammate sign-off',
            },
            {
              value: 'lead',
              label: 'Tech Lead',
              description: 'Owner team approval',
            },
            {
              value: 'qa',
              label: 'QA + Lead',
              description: 'Formal release gate',
            },
          ]}
          variant="card"
        />
      </FormField>

      <FormField<typeof ReleaseReadinessSchema> name="notes" label="Release Notes" required>
        <Textarea
          placeholder="Summarize risk, migration notes, and rollback strategy..."
          rows={4}
        />
      </FormField>

      <FormField<typeof ReleaseReadinessSchema>
        name="rolloutConfirmed"
        label="Rollback Prepared"
        required
      >
        <Checkbox label="I confirmed rollback commands and owner on-call availability." />
      </FormField>

      <Button type="submit">Approve Release</Button>
      <Show when={approvedRelease()}>
        {(message) => <p class="text-success text-sm">{message()}</p>}
      </Show>
    </Form>
  )
}
```

### Incident Escalation Policy

Configure nested policy fields for severity routing and automatic rollback behavior.

```tsx
function IncidentEscalationPolicy() {
  const [submittedPolicy, setSubmittedPolicy] = createSignal<string>()
  const form = createForm({
    schema: IncidentPolicySchema,
    initialInput: {
      policy: {
        name: '',
        severity: 'p1',
        notifyEmail: '',
        autoRollback: true,
        summary: '',
      },
    },
  })

  return (
    <Form
      of={form}
      onSubmit={(output) => setSubmittedPolicy(`Saved ${output.policy.name}.`)}
      class="mx-auto max-w-2xl w-full space-y-4"
    >
      <FormField<typeof IncidentPolicySchema>
        name={['policy', 'name']}
        label="Policy Name"
        required
      >
        <Input placeholder="payments-latency-spike" />
      </FormField>

      <FormField<typeof IncidentPolicySchema>
        name={['policy', 'severity']}
        label="Default Severity"
        required
      >
        <Select
          options={[
            { label: 'P1 - Critical', value: 'p1' },
            { label: 'P2 - Major', value: 'p2' },
            { label: 'P3 - Minor', value: 'p3' },
          ]}
          placeholder="Select severity"
        />
      </FormField>

      <FormField<typeof IncidentPolicySchema>
        name={['policy', 'notifyEmail']}
        label="Escalation Email"
        required
      >
        <Input type="email" placeholder="oncall@acme.dev" />
      </FormField>

      <FormField<typeof IncidentPolicySchema>
        name={['policy', 'autoRollback']}
        label="Auto Rollback"
        description="Trigger rollback when alert duration crosses the policy threshold."
      >
        <Switch />
      </FormField>

      <FormField<typeof IncidentPolicySchema>
        name={['policy', 'summary']}
        label="Policy Summary"
        required
      >
        <Textarea
          placeholder="Describe conditions and handoff details for incident response."
          rows={3}
        />
      </FormField>

      <Button type="submit">Save Escalation Policy</Button>
      <Show when={submittedPolicy()}>
        {(message) => <p class="text-success text-sm">{message()}</p>}
      </Show>
    </Form>
  )
}
```

### Access Request Review

Review temporary access requests with scoped permissions and required reviewers.

```tsx
function AccessRequestReview() {
  const [submittedRequest, setSubmittedRequest] = createSignal<string>()
  const form = createForm({
    schema: AccessRequestSchema,
    initialInput: {
      requester: '',
      reason: '',
      temporary: true,
      scopes: ['repo:read'],
      reviewers: ['security'],
    },
  })

  return (
    <Form
      of={form}
      onSubmit={(output) => setSubmittedRequest(`Request submitted for ${output.requester}.`)}
      class="mx-auto max-w-2xl w-full space-y-4"
    >
      <FormField<typeof AccessRequestSchema> name="requester" label="Requester" required>
        <Input placeholder="alex.chen" />
      </FormField>

      <FormField<typeof AccessRequestSchema> name="reason" label="Business Reason" required>
        <Textarea
          placeholder="Need short-term access for production incident mitigation."
          rows={3}
        />
      </FormField>

      <FormField<typeof AccessRequestSchema>
        name="temporary"
        label="Temporary Access"
        description="Enable automatic expiry for this permission grant."
      >
        <Switch />
      </FormField>

      <FormField<typeof AccessRequestSchema> name="scopes" label="Requested Scopes" required>
        <CheckboxGroup
          items={[
            { value: 'repo:read', label: 'Repository Read', description: 'View code and PRs' },
            {
              value: 'repo:write',
              label: 'Repository Write',
              description: 'Push and merge changes',
            },
            {
              value: 'deploy:prod',
              label: 'Production Deploy',
              description: 'Trigger release pipelines',
            },
          ]}
          variant="card"
        />
      </FormField>

      <FormField<typeof AccessRequestSchema> name="reviewers" label="Required Reviewers" required>
        <CheckboxGroup
          items={[
            {
              value: 'security',
              label: 'Security Team',
              description: 'Permission boundary review',
            },
            {
              value: 'platform',
              label: 'Platform Team',
              description: 'Infrastructure and ops review',
            },
            { value: 'manager', label: 'Line Manager', description: 'Business ownership approval' },
          ]}
        />
      </FormField>

      <Button type="submit">Submit Access Request</Button>
      <Show when={submittedRequest()}>
        {(message) => <p class="text-success text-sm">{message()}</p>}
      </Show>
    </Form>
  )
}
```

## API Reference

### Attributes

#### `root`

Native form element managed by Formisch.

### Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| class | ClassValue | — | Class applied to the component root or trigger element. |
| classes | FormT.Classes \| undefined | — | — |
| onSubmit | SubmitEventHandler<TSchema> \| undefined | — | Called with validated schema output and the native submit event. |
| ref | JSX.HTMLElementTags["form"] extends { ref?: infer Ref; } ? Ref : never \| undefined | — | — |
| style | JSX.CSSProperties \| undefined | — | — |
| styles | FormT.Styles \| undefined | — | — |

### Data Attributes

State and slot attributes exposed for styling hooks and selectors.

| Attribute | Type | Description |
| --- | --- | --- |
| data-submitting | string \| undefined | State or slot attribute exposed for styling hooks and selectors. |

### Inherited

#### From `@formisch/solid`

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| children | JSX.Element | — | The child elements to render within the form. |
| of* | FormStore<TSchema> | — | The form store instance. |
