Skip to content

CommandForm

Editing a command should not require a second copy of its values in React state. CommandForm owns one generated command instance and binds its fields to that instance. Submitting the form executes the values you edited.

Before using these examples, configure Arc in React and proxy generation. Import a generated command class, not a TypeScript interface or an empty subclass of Command: execution needs the generated route, property descriptors, and validation metadata.

The component below is a runnable frontend checkpoint in that configured application. It expects a generated UpdateProfile at ./commands/UpdateProfile with name and email string properties; adapt the import to your configured output directory. Its backend endpoint and rules are shown in Validation. That example returns profile details to demonstrate a standalone Arc response; it does not persist them or require Chronicle.

import { CommandForm, InputTextField, useIsCommandExecuting } from '@cratis/arc.react/commands';
import { UpdateProfile } from './commands/UpdateProfile';
function SaveButton() {
const isExecuting = useIsCommandExecuting();
return <button type="submit" disabled={isExecuting}>{isExecuting ? 'Saving…' : 'Save'}</button>;
}
export function ProfileForm() {
return (
<CommandForm
command={UpdateProfile}
initialValues={{ name: '', email: '' }}
onSuccess={() => window.alert('Profile accepted')}
>
<InputTextField<UpdateProfile> value={c => c.name} title="Name" placeholder="Your name" />
<InputTextField<UpdateProfile> value={c => c.email} title="Email" type="email" />
<SaveButton />
</CommandForm>
);
}

Edit a field, leave it to see rule failures, then submit valid values. SaveButton reads the surrounding form’s execution state because it renders inside the form. Hooks called in ProfileForm itself would be outside that provider. For a toolbar or dialog footer, use formRef and onStateChange.

type="email" chooses an HTML control; it does not define an Arc email rule. The form uses noValidate, so browser constraint validation does not block submission. See required fields and validation rules.

command is required; children accepts React nodes. The callbacks below use the generated instance type TCommand and the response type TResponse (default object).

PropDefaultContract
commandRequiredConstructor<TCommand>; use the generated command class.
initialValuesUnsetPartial<TCommand> seed and change-tracking baseline. Undefined values supply nothing; changing this prop alone after mount does not repopulate the command.
currentValuesUnsetReactive Partial<TCommand> overlay. Present keys are written, including explicit null/undefined where the property type permits them; absent keys are left alone.
populateFromQueryUnsetSingle-instance query constructor used to populate field baselines.
populateFromObservableQueryUnsetObservable counterpart; choose one population source.
populateFromQueryArgsUnsetArgument object for either population source.
validateOn'blur''blur', 'change', or 'both'; controls when interaction errors appear, not whether silent validation runs.
validateAllFieldsOnChangefalseDisplay the full validation result rather than merging only the interacted field’s errors.
validateOnInitfalseDisplay initialization/population validation errors. Silent validation still runs when false.
autoServerValidatefalseOpt into pre-submit server validation; submission still validates on the server.
autoServerValidateThrottle500Delay in milliseconds for the typing-triggered server-validation timer, not a global request limiter.
onFieldValidateUnsetSynchronous (command, fieldName, oldValue, newValue) => string | undefined; supplies a custom field message.
onFieldChangeUnset(command, fieldName, oldValue, newValue, validationInfo?) => void; interaction notification, not a fresh asynchronous validation verdict.
onBeforeExecuteUnsetSynchronous (command: TCommand) => TCommand; return the executable command instance.
onSuccessUnset(response: TResponse) => void.
onFailedUnset(result: ICommandResult<TResponse>) => void; receives the original result when execution fails.
onExceptionUnset(messages: string[], stackTrace: string) => void; receives original diagnostics when hasExceptions is true.
onUnauthorizedUnset() => void.
onValidationFailureUnset(validationResults: ValidationResult[]) => void.
formRefUnsetReact.Ref<CommandFormHandle> for parent execution and live state reads.
onStateChangeUnset(state: CommandFormState) => void for reactive parent state.
showTitlestrueEnable built-in field titles. Custom renderers must honor the intended presentation themselves.
showErrorstrueShow automatic field errors and form-level exception feedback, including the custom exception renderer. Does not suppress messages independently rendered by custom fields or summaries.
exceptionMessage'An unexpected error occurred. Please try again.'Safe user-facing string; supports localization and preserves an explicitly empty string.
exceptionDisplayComponentUnsetReact.ComponentType<ExceptionDisplayProps> replacing the default exception panel; receives only { message: string } and is not invoked when showErrors is false.
fieldContainerComponentUnsetComponent receiving FieldContainerProps.
fieldDecoratorComponentUnsetComponent receiving FieldDecoratorProps.
errorDisplayComponentUnsetComponent receiving ErrorDisplayProps for field validation errors, not form-level exceptions.
tooltipComponentUnsetComponent receiving TooltipWrapperProps.
errorClassName'p-error'Default error element’s CSS class.
iconAddonClassName'p-inputgroup-addon'Default icon wrapper’s CSS class.

Exception feedback uses safe text rather than raw server diagnostics. See safe exception customization for localization and replacement renderers, and exception diagnostics and display for callback and context behavior.

Use initialValues for the initial seed and baseline, as in the example above; use currentValues for a reactive overlay. Changing initialValues alone after mount does not repopulate the command.

See Data loading for precedence and population, Validation for state limitations, and Customization for renderer contracts.

Fields bind through fragments, HTML elements, and custom layout components. Use simple accessors such as c => c.name; binding resolves a property name, not an arbitrary computed expression. CommandForm.Column groups columns; its responsive styling needs the CSS described in Layouts.