dimah-formv0.2.0

Field Types

Built-in types, validation constraints, showWhen operators, and $Infer mappings.

Seven built-in types in @dimah-form/core. Each one has a definition schema, a server validator, and an $Infer mapping.


Built-In Field Types Catalog

TypeAnswer TypeSchema ConstraintsDescription
textstringminLength?: number
maxLength?: number
pattern?: string (regex)
Single-line or multi-line text input. Validates length and regex pattern.
numbernumbermin?: number
max?: number
integer?: boolean
Numeric input. Validates minimum, maximum, and integer constraints.
booleanbooleanCheckbox or toggle switch. Values are strictly true or false.
selectstringoptions: SelectOption[]Single-choice dropdown or radio group. Answer must match an option value.
multiSelectstring[]options: SelectOption[]Multi-choice checkbox group or tag selector. Answer must be an array of valid option values without duplicates.
emailstringEmail address input. Validates standard RFC 5322 email formatting.
datestringmin?: string (YYYY-MM-DD)
max?: string (YYYY-MM-DD)
Calendar date in YYYY-MM-DD ISO format. Validates date boundaries.

Select Option Structure

Options passed to select or multiSelect fields follow this schema:

type SelectOption = {
  /** The persisted answer value (e.g., "us", "uk", "de") */
  value: string;

  /** Display label for the UI (defaults to value if omitted) */
  label?: string;

  /** Custom metadata for icons, descriptions, or badge tags */
  meta?: Record<string, unknown>;
};

Conditional Visibility (showWhen)

The showWhen property dynamically hides or shows fields based on the respondent's answers.

Automatic Cleanup: When a field is conditionally hidden, its answer is automatically stripped from the submitted response so outdated answers never persist to your database.

1. Leaf Conditions

equals

Matches when the target field's answer strictly equals the specified value:

{
  id: "githubHandle",
  type: "text",
  label: "GitHub Handle",
  showWhen: { field: "role", equals: "developer" },
}

notEquals

Matches when the target field's answer is not equal to the specified value:

{
  id: "reason",
  type: "text",
  label: "Reason for cancellation",
  showWhen: { field: "plan", notEquals: "free" },
}

includes

Matches when a multiSelect array answer contains the specified value:

{
  id: "reactExperience",
  type: "number",
  label: "Years of React Experience",
  showWhen: { field: "skills", includes: "react" },
}

2. Compound Conditions (all / any)

all (Logical AND)

Matches only when all nested conditions evaluate to true:

showWhen: {
  all: [
    { field: "department", equals: "engineering" },
    { field: "isLead", equals: true },
  ],
}

any (Logical OR)

Matches when at least one nested condition evaluates to true:

showWhen: {
  any: [
    { field: "country", equals: "US" },
    { field: "country", equals: "CA" },
  ],
}

Type Inference ($Infer) Mapping

When defining forms with defineForm(), TypeScript derives the answer type automatically:

lib/forms/example.ts
import { defineForm } from "@dimah-form/server";

export const exampleForm = defineForm({
  title: "Example",
  slug: "example",
  fields: [
    { id: "name", type: "text", required: true },
    { id: "age", type: "number" }, // Optional because required is omitted
    {
      id: "role",
      type: "select",
      required: true,
      options: [{ value: "admin" }, { value: "user" }],
    },
    {
      id: "tags",
      type: "multiSelect",
      options: [{ value: "frontend" }, { value: "backend" }],
    },
  ],
});

The resulting $Infer answer type is strictly typed:

type ExampleAnswers = Form["$Infer"]["answers"]["example"];

// Resolves to:
// {
//   name: string;
//   role: "admin" | "user";
//   age?: number;
//   tags?: ("frontend" | "backend")[];
// }

Next Steps

On this page