useSubmitActionTriggers
Manages automatic execution of submit actions based on non-submit triggers like field changes, blur events, step transitions, and idle timeouts. This is what powers real-time features like auto-saving on field change or sending analytics on step exit.
You probably don’t need this directly. The
<Form>component wires it up internally whenever your config hassubmitActions. Use it when building custom trigger logic on top of your own form.
Signature
import { useSubmitActionTriggers } from '@saastro/forms';
const { triggerFieldChange, triggerFieldBlur, triggerManual, hasActionsForTrigger } =
useSubmitActionTriggers({
config,
getValues,
currentStep,
onActionExecuted,
onActionError,
enabled,
});
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
config | FormConfig | Yes | Form configuration with submit actions |
getValues | () => Record<string, unknown> | Yes | Function returning the current form values — pass methods.getValues itself (avoids re-renders) |
currentStep | string | Yes | Active step ID |
onActionExecuted | (result) => void | No | Called after an action completes |
onActionError | (error, actionName) => void | No | Called when an action fails |
enabled | boolean | No | Enable/disable all triggers (default: true) |
getValuesis a function reference, not a values object. Passmethods.getValuesdirectly — do not call it (methods.getValues()). The hook reads values lazily at fire time, so triggers always see the latest data without subscribing to every keystroke.
Return Value
| Property | Type | Description |
|---|---|---|
triggerFieldChange | (fieldName, value) => void | Trigger onFieldChange actions (debounced) |
triggerFieldBlur | (fieldName) => void | Trigger onFieldBlur actions (immediate) |
triggerManual | (actionIds?) => Promise<SubmitActionsResult> | Manually trigger specific actions |
hasActionsForTrigger | (triggerType, triggerValue?) => boolean | Check if any actions exist for a trigger type |
Trigger Types
| Trigger | When It Fires | Behavior |
|---|---|---|
onFieldChange | User changes a field value | Debounced (debounceMs of the first matching action, default 300ms, per field) |
onFieldBlur | User leaves a field | Immediate |
onStepEnter | User navigates to a step | Automatic (via step change detection) |
onStepExit | User leaves a step | Automatic (via step change detection) |
onDelay | User is idle for delayMs ms (default 30000) | Automatic (listens to mousedown, keydown, touchstart, scroll; re-arms after each activity) |
manual | Programmatic trigger | Via triggerManual() call |
onSubmitactions are not handled by this hook — they run inside the submit pipeline when the form is submitted.hasActionsForTrigger('onSubmit')still reports them.
Example: Manual Trigger
import { useFormState, useSubmitActionTriggers } from '@saastro/forms';
import type { FormConfig } from '@saastro/forms';
function SaveDraftButton({ config }: { config: FormConfig }) {
const { methods, currentStepId } = useFormState({ config, fields: config.fields });
const { triggerManual, hasActionsForTrigger } = useSubmitActionTriggers({
config,
getValues: methods.getValues, // pass the function, don't call it
currentStep: currentStepId,
});
const saveDraft = async () => {
// Check if there are manual actions available
if (hasActionsForTrigger('manual')) {
const result = await triggerManual(['save-draft']);
console.log('Draft saved:', result.allSuccessful);
}
};
return <button onClick={saveDraft}>Save draft</button>;
}
Notes
triggerManualignoresenabled— it executes even whenenabledisfalse. The automatic effects andtriggerFieldChange/triggerFieldBlurdo respect it.triggerFieldChangeignores itsvalueargument; values are read viagetValues()when the debounced action actually fires.- The hook’s option and return interfaces are not exported types — only the function itself is public.
- All debounce and idle timers are cleared on unmount.
Related
- Submit & Actions — Configuring submit actions with different triggers