Form Wire
Core Concepts

Schema

How Zod schemas drive form field generation

Form Wire introspects your Zod schema to generate field metadata automatically. You don't define fields manually — the schema is the source of truth.

Supported Field Types

Zod TypeForm Field KindUI Control
z.string()string<input type="text">
z.email()string<input type="email">
z.coerce.number()number<input type="number">
z.coerce.date()date<input type="date">
z.boolean()boolean<input type="checkbox">
z.literal(true)boolean<input type="checkbox"> (must be checked)
z.enum([...])select<select>
z.literal("value")select<select> (single option)
z.file()file<input type="file">
z.string().array()stringArrayRepeated text inputs
z.object({...}).array()objectArrayFieldset groups
z.object({...})Nested group<fieldset>

String Subtypes

Form Wire detects common string formats and maps them automatically:

z.email()           // → type="email"
z.coerce.number()    // → type="number"
z.coerce.date()      // → type="date"
z.string()           // → type="text"

Force a textarea using the component option in field config:

createFormWire(schema, {
  fields: {
    bio: { label: "Bio", component: "textarea" },
  },
});

Optional vs Required

Zod determines whether a field is required:

z.string()           // required (must be non-empty)
z.string().optional() // not required
z.string().nullable() // not required, parses as null when empty

Select Fields

Any union of string literals generates a <select>:

z.enum(["pending", "active", "paused"])
// → <select> with three options

Enum with Labels

Option labels come from the field config options or are generated from the enum values:

createFormWire(schema, {
  fields: {
    status: {
      label: "Status",
      placeholder: "Choose a status",
    },
  },
});

Schema Metadata

Use withMeta() to attach label and description directly to schema nodes:

import { withMeta } from "@form-wire/core";

const schema = z.object({
  name: withMeta(z.string().min(1), {
    label: "Full Name",
    description: "Your legal name",
    placeholder: "Ada Lovelace",
  }),
});

Metadata from withMeta is merged with field config from createFormWire — config takes precedence.

On this page