# Field Types (https://form.dimah.dev/docs/field-types)



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 [#built-in-field-types-catalog]

| Type              | Answer Type | Schema Constraints                                                             | Description                                                                                                     |
| :---------------- | :---------- | :----------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------- |
| **`text`**        | `string`    | `minLength?: number`<br />`maxLength?: number`<br />`pattern?: string` (regex) | Single-line or multi-line text input. Validates length and regex pattern.                                       |
| **`number`**      | `number`    | `min?: number`<br />`max?: number`<br />`integer?: boolean`                    | Numeric input. Validates minimum, maximum, and integer constraints.                                             |
| **`boolean`**     | `boolean`   | —                                                                              | Checkbox or toggle switch. Values are strictly `true` or `false`.                                               |
| **`select`**      | `string`    | `options: SelectOption[]`                                                      | Single-choice dropdown or radio group. Answer must match an option `value`.                                     |
| **`multiSelect`** | `string[]`  | `options: SelectOption[]`                                                      | Multi-choice checkbox group or tag selector. Answer must be an array of valid option values without duplicates. |
| **`email`**       | `string`    | —                                                                              | Email address input. Validates standard RFC 5322 email formatting.                                              |
| **`date`**        | `string`    | `min?: string` (YYYY-MM-DD)<br />`max?: string` (YYYY-MM-DD)                   | Calendar date in `YYYY-MM-DD` ISO format. Validates date boundaries.                                            |

***

## Select Option Structure [#select-option-structure]

Options passed to `select` or `multiSelect` fields follow this schema:

```ts
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`) [#conditional-visibility-showwhen]

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

<Callout type="info">
  **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.
</Callout>

### 1. Leaf Conditions [#1-leaf-conditions]

#### `equals` [#equals]

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

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

#### `notEquals` [#notequals]

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

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

#### `includes` [#includes]

Matches when a `multiSelect` array answer contains the specified value:

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

### 2. Compound Conditions (`all` / `any`) [#2-compound-conditions-all--any]

#### `all` (Logical AND) [#all-logical-and]

Matches only when **all** nested conditions evaluate to `true`:

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

#### `any` (Logical OR) [#any-logical-or]

Matches when **at least one** nested condition evaluates to `true`:

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

***

## Type Inference (`$Infer`) Mapping [#type-inference-infer-mapping]

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

```ts title="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:

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

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

***

## Next Steps [#next-steps]

<Cards>
  <Card title="Custom Fields" href="/docs/custom-fields" description="Create custom validators and $Infer type mappings with defineFieldType." />

  <Card title="Widgets" href="/docs/widgets" description="Render UI widgets for all 7 built-in field types." />

  <Card title="Protocol" href="/docs/protocol" description="Inspect request and response payload schemas." />
</Cards>
