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