icon

Morainev0.5.0

Form
formsform

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.

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.

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="[email protected]" />
</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.

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.

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="[email protected]" />
</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.

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#

Slotroot0 attributes
Native form element managed by Formisch.
No attribute metadata for this slot.

Props#

PropTypeDefaultDescription
classClassValue
Class applied to the component root or trigger element.
classesFormT.Classes | undefined
onSubmitSubmitEventHandler<TSchema> | undefined
Called with validated schema output and the native submit event.
refJSX.HTMLElementTags["form"] extends { ref?: infer Ref; } ? Ref : never | undefined
styleJSX.CSSProperties | undefined
stylesFormT.Styles | undefined

Inherited#

From @formisch/solid
PropTypeDefaultDescription
childrenJSX.Element
The child elements to render within the form.
of*FormStore<TSchema>
The form store instance.