Skip to main content

Form Actions

Form Actions are the buttons rendered by a DyonaForm: the built-in submit and back actions plus application-defined custom actions. They configure the form UI and call the React callbacks supplied to DyonaForm.

They are not the generic Action Engine. Form Actions do not use DyonaAction, executors, action scopes, records, parameters, results, or refresh directives. Use Form Actions for a form's local workflow; use Action Engine when the application needs to execute a typed business action.

Configuration​

type DyonaFormActionsConfig = {
submit?: DyonaFormActionButtonConfig;
back?: DyonaFormActionButtonConfig;
custom?: DyonaFormCustomActionConfig[];
disableOtherActionsWhileRunning?: boolean;
layout?: 'horizontal' | 'vertical';
wrap?: boolean;
};

type DyonaFormActionButtonConfig = {
label?: string;
icon?: string;
shortcut?: string;
tooltip?: string;
variant?: 'text' | 'outlined' | 'contained';
loadingLabel?: string;
showSpinner?: boolean;
cancelable?: boolean;
};

type DyonaFormCustomActionConfig = DyonaFormActionButtonConfig & {
id: string;
label: string;
validate?: boolean;
};

submit configures the button that invokes onSubmit(values, {signal}); it validates the form before calling the handler. back configures the button that invokes onBack({signal}). A button is rendered only when its corresponding callback is supplied.

custom adds buttons that invoke onAction(id, values, {signal}). Each custom action has a unique, non-empty id and a required label; custom buttons are rendered when both custom actions and onAction are provided.

const schema: DyonaFormSchema = {
title: 'Customer',
actions: {
back: { label: 'Back', icon: 'ArrowBack' },
custom: [{
id: 'preview',
label: 'Preview',
icon: 'Preview',
validate: false,
variant: 'outlined',
shortcut: 'Ctrl+P',
}],
submit: { label: 'Save', loadingLabel: 'Saving…', cancelable: true },
},
tabs: [/* ... */],
};

<DyonaForm
schema={schema}
onBack={async ({signal}) => { /* navigate, honoring signal if needed */ }}
onAction={async (id, values, {signal}) => {
if (id === 'preview') { /* use values; pass signal to abortable work */ }
}}
onSubmit={async (values, {signal}) => { /* save values */ }}
/>

Validation and async work​

submit always validates and normalizes values before onSubmit. A custom action validates only when validate: true; otherwise it receives normalized values without blocking on form validation. back has no values and does not validate.

Handlers may be synchronous or return a promise. While a handler is pending, its button shows loadingLabel (or its normal label) and, by default, a spinner. DYONA Form runs only one action at a time. By default, disableOtherActionsWhileRunning is true, so the other buttons are disabled; setting it to false keeps them visually enabled, but does not permit a second action to start.

Every execution receives a fresh AbortSignal in its context. With cancelable: true, the running action also shows a localized Cancel button. Clicking it aborts that signal; make async work abort-aware (for example, pass signal to fetch) and treat its abort rejection as cancellation.

Button appearance and keyboard access​

All button configurations accept icon, tooltip, and shortcut. icon is an MUI icon name. A shortcut activates the action and is included in its tooltip; tooltip supplies the tooltip text. Shortcuts must be valid and unique among form actions.

Use variant to select MUI's text, outlined, or contained treatment. The defaults are contained for submit and outlined for back and custom actions. layout defaults to horizontal; set it to vertical to stack the action groups. wrap defaults to true and controls whether they wrap when space is limited.

Defaults​

  • Submit label: localized Save; back label: localized Back.
  • loadingLabel defaults to the action's normal label.
  • showSpinner defaults to true; cancelable defaults to false.
  • custom defaults to an empty array, layout to horizontal, wrap to true, and disableOtherActionsWhileRunning to true.

For typed business operations that return results or request data refreshes, see Action Engine.

Try it live in the Lab