---
title: CommandForm
editUrl: https://github.com/Cratis/Components/edit/main/Documentation/CommandForm/index.md
description: Build type-safe Arc command forms with reusable fields, validation, and automatic value binding.
---


The `CommandForm` component provides form field components for building command input forms with automatic type handling and validation.

## Purpose

CommandForm offers a complete set of form field components designed to work seamlessly with Cratis Arc commands. It handles different data types, validation, and integration with command execution.

## Key Features

- Field generation from the command's own properties with [`AutoCommandForm`](/components/commandform/auto-command-form/)
- Support for various input types (text, number, date, boolean, etc.)
- Built-in validation
- Integration with `CommandForm`, `CommandDialog`, `CommandStepper`, and `StepperCommandDialog`
- Type-safe field handling

## Available Field Components

The CommandForm module exports Cratis-owned semantic fields built with native controls and documented keyboard, naming, and validation behavior. Each field uses `asCommandFormField` for automatic value binding, validation state, and Arc command integration.

Import fields from `@cratis/components/CommandForm` or `@cratis/components/CommandForm/fields`; both subpaths resolve to the same module, so pick one and use it consistently.

See the field type pages in this section for documentation on each available field component. To generate a form's fields from a command's own properties instead of writing them out by hand, see [AutoCommandForm](/components/commandform/auto-command-form/).

## Type-Safe Binding

All field components bind to a property on the command via a `value` accessor function. Pass the command type as a generic type parameter so the accessor is fully typed:

```tsx
// ✅ Correct: full type safety — 'c' is typed as MyCommand
<InputTextField<MyCommand> value={c => c.title} />

// ❌ Incorrect: missing type parameter — 'c' is 'unknown'
<InputTextField value={c => c.title} />
```

The `value` prop accepts a function of the form `(instance: TCommand) => unknown`.

## Integration

CommandForm fields are children of Arc's `CommandForm` or of a Components command surface such as `CommandDialog`. The excerpt assumes `MyCommand` is a generated command proxy and `visible` / `setVisible` is component state:

```tsx
import { CommandDialog } from '@cratis/components/CommandDialog';
import {
    InputTextField,
    NumberField,
    CheckboxField,
} from '@cratis/components/CommandForm';

<CommandDialog<MyCommand>
    command={MyCommand}
    title='Edit item'
    visible={visible}
    onSuccess={() => setVisible(false)}
    onCancel={() => setVisible(false)}
>
    <InputTextField<MyCommand> value={(c) => c.title} title='Title' />
    <NumberField<MyCommand> value={(c) => c.quantity} title='Quantity' />
    <CheckboxField<MyCommand> value={(c) => c.active} label='Active' />
</CommandDialog>;
```

`title` is required on `CommandDialog`. Outside `useDialog`, close the dialog yourself from `onSuccess` and `onCancel`; see [CommandDialog](/components/commanddialog/#controlled-visibility).

## Field defaults and command values

Each field page states what the control shows while the bound property is unset, such as an unchecked box for `CheckboxField` or `0` for `NumberField`. That is only what the control **shows**. It is not written to the command until the user edits the field. A non-optional property that is still unset fails Arc's client validation, so the form stays invalid and a `CommandDialog` keeps confirm disabled. When the displayed default is an acceptable answer, seed it through `initialValues`; see [Initialize command values](/components/commanddialog/#initialize-command-values).

## Accessible names and validation errors

Every Components field associates its primary native control or semantic group with Arc's `title` and validation messages:

- `title` becomes the default accessible name while Arc continues rendering the visible field title.
- Validation messages are referenced through `aria-describedby` and remain visible through Arc's normal error presentation.
- `id`, `aria-label`, and `aria-describedby` can override or extend the generated values on every field.
- Component-specific `pt` attributes remain fallback values; named accessibility props take precedence.

Checkboxes and switches prefer their inline `label`; radio options use their option labels while the `RadioGroupField` / `RatingField` group uses `title`.

## Populating Initial Values from a Query

Every field here is built with `asCommandFormField` from `@cratis/arc.react/commands`, so each one automatically supports `CommandForm`'s `populateFromQuery`/`populateFromObservableQuery` props - the form fetches a single-instance query itself and seeds its fields from the result, matched onto the command by property name:

```tsx
import { CommandForm } from '@cratis/arc.react/commands';
import { InputTextField } from '@cratis/components/CommandForm';
import { GetUserProfile } from './queries';
import { UpdateProfile } from './commands';

<CommandForm
    command={UpdateProfile}
    populateFromQuery={GetUserProfile}
    populateFromQueryArgs={{ userId }}
>
    <InputTextField<UpdateProfile> value={(c) => c.firstName} title='First name' />
    <InputTextField<UpdateProfile> value={(c) => c.lastName} title='Last name' />
</CommandForm>;
```

Two field props refine this per field - both work on every field type in this package, since they come from the shared `asCommandFormField` wrapper:

- `noInitialValue` - skip this field entirely, even if the query result has a same-named property.
- `initialValue` - override how the field's value is derived from the query result, either a property accessor matched by name or a function composing a value from the whole result.

See Arc's [Populating a Form from a Query](https://www.cratis.io/arc/frontend/react/command-form/data-loading/) for the full behavior, including how the populated data becomes the form's change-tracking baseline.

## How a child is recognized as a field

`CommandForm`, `CommandDialog`, and `CommandStepper` inspect each child's component type. A field carries `isCommandFormField: true`; a column carries `isCommandFormColumn: true`. The legacy `displayName` values remain permanent fallbacks so independently versioned Components and Arc packages interoperate in either upgrade order.

Use `asCommandFormField` from `@cratis/arc.react/commands` for custom fields; it stamps the marker automatically. For a hand-rolled field or column, use `markAsCommandFormField` or `markAsCommandFormColumn` from `@cratis/components/CommandForm`.

The marker is a plain shared property rather than a package-private symbol, so a component marked by Arc is recognized by Components and vice versa. Build transforms may rewrite `displayName` without silently breaking binding.
