Skip to main content

useSplitPaymentsForm

useSplitPaymentsForm(props: UseSplitPaymentsFormProps): UseSplitPaymentsFormResult

Headless React Hook Form hook for splitting an employee's Direct Deposit across multiple bank accounts.

Remarks

Supports two split modes: Percentage (whole-number shares that sum to 100) and Amount (dollar amounts, with the last-priority split absorbing the remainder). Always operates in update mode against the employee's existing payment method.

The Percentage sum-to-100 invariant is surfaced via status.hasPercentageImbalance (not as a per-field error). With the default validationMode: 'onSubmit', the imbalance flag appears after the first failed Save and clears live as the user corrects the total.

Example

Example
import {
useSplitPaymentsForm,
SDKFormProvider,
type SplitByValue,
type UseSplitPaymentsFormReady,
} from '@gusto/embedded-react-sdk'

function SplitPaycheckScreen({ employeeId }: { employeeId: string }) {
const splitForm = useSplitPaymentsForm({ employeeId })

if (splitForm.isLoading) return null
return <SplitPaycheckReady splitForm={splitForm} />
}

function SplitPaycheckReady({ splitForm }: { splitForm: UseSplitPaymentsFormReady }) {
const { Fields } = splitForm.form
const { hasPercentageImbalance, percentageTotal } = splitForm.status

return (
<SDKFormProvider formHookResult={splitForm}>
<form
onSubmit={e => {
e.preventDefault()
void splitForm.actions.onSubmit()
}}
>
{hasPercentageImbalance && (
<div role="alert">Splits must total 100%. Currently {percentageTotal}%.</div>
)}
<Fields.SplitBy label="Split by" getOptionLabel={(value: SplitByValue) => value} />
{Fields.splits.map(split => (
<split.Field
key={split.uuid}
label={split.name ?? 'Account'}
min={0}
/>
))}
<button type="submit" disabled={splitForm.status.isPending}>Save</button>
</form>
</SDKFormProvider>
)
}

Props

UseSplitPaymentsFormProps

Props for useSplitPaymentsForm.

PropertyTypeDescription
employeeIdstringEmployee whose payment splits are being edited.
optionalFieldsToRequire?SplitPaymentsFormOptionalFieldsToRequireOverride optional fields to be required. Currently a no-op — splitBy and priority are always required, and per-split splitAmount required-ness is automatic.
shouldFocusError?booleanAuto-focus the first invalid field on submit. Set to false when using composeSubmitHandler. Defaults to true.
validationMode?"onChange" | "onBlur" | "onSubmit" | "onTouched" | "all"When validation runs. Passed through to react-hook-form. Defaults to 'onSubmit'.

Returns

UseSplitPaymentsFormResult

A loading-state result while the payment method and bank accounts are loading, or a UseSplitPaymentsFormReady once ready.

UseSplitPaymentsFormResult

UseSplitPaymentsFormResult = HookLoadingResult | UseSplitPaymentsFormReady

Return type of useSplitPaymentsForm — a discriminated union on isLoading.


UseSplitPaymentsFormReady

Ready-state return value of useSplitPaymentsForm.

PropertyTypeDescription
actionsobjectActions that mutate the form or submit it.
actions.onSubmit() => Promise<HookSubmitResult<EmployeePaymentMethod> | undefined>Submit the form. Returns the updated payment method on success or undefined on validation/mutation failure.
actions.reorderSplits(orderedUuids: string[]) => voidReorder splits by uuid (Amount mode). Pass the ordered list of split uuids; the last uuid becomes the remainder. The hook writes the new priority map and re-anchors the remainder's splitAmount to null (clearing the previous remainder to 0).
dataobjectServer-fetched data and derived working values.
data.bankAccountsEmployeeBankAccount[]All bank accounts available to allocate splits across.
data.paymentMethodEmployeePaymentMethodThe employee's current payment method.
data.remainderIdstringUUID of the split that absorbs the remainder in Amount mode (always the last by priority).
data.splitsWorkingSplit[]The current working split entries, one per bank account.
errorHandlingHookErrorHandlingError state and recovery actions.
formobjectForm bindings: pre-bound field components, per-field metadata, submission values, and react-hook-form internals.
form.FieldsSplitPaymentsFormFields-
form.fieldsMetadataSplitPaymentsFormFieldsMetadata-
form.getFormSubmissionValues() => SplitPaymentsFormData | undefined-
form.hookFormInternalsHookFormInternals<SplitPaymentsFormData>-
isLoadingfalseAlways false in this branch; discriminates from HookLoadingResult.
statusobjectSubmission state and reactive form-level flags.
status.hasPercentageImbalancebooleantrue after a failed Percentage-mode Save when the splits don't sum to 100; clears live as the user corrects the total. Follows the standard react-hook-form validation lifecycle (controlled by validationMode). Only surfaces in Percentage mode.
status.isPendingbooleantrue while the update mutation is in flight.
status.mode"update"Always 'update' — the hook always edits an existing payment method.
status.percentageTotalnumberLive sum of splitAmount values; useful for displaying the current total in Percentage mode.
status.splitBy"Percentage" | "Amount"Current splitBy value, reactively tracked.

Fields

SplitPaymentsFormFields

Field components exposed by useSplitPaymentsForm on form.Fields.

PropertyTypeDescription
SplitByComponentType<SplitByFieldProps>Radio group bound to splitBy; selects Percentage or Amount split mode.
splitsSplitFieldEntry[]One entry per bank account, each carrying a pre-bound Field component for the per-split amount.

SplitBy

Radio group bound to splitBy; selects Percentage or Amount split mode.

<form.Fields.SplitBy
label="Split by"
validationMessages={{ REQUIRED: '…' }}
/>

SplitByFieldProps

HookFieldProps<RadioGroupHookFieldProps<SplitPaymentsFormRequiredValidation, SplitByValue>>

Props accepted by useSplitPaymentsForm's Fields.SplitBy component.

PropertyTypeDescription
labelstringVisible label rendered above the field.
FieldComponent?ComponentType<RadioGroupProps>Replaces the default radio group UI component; must accept the same props as RadioGroupProps.
getOptionLabel?(entry: SplitByValue) => stringMaps a raw option entry to its display label; when omitted, options use the labels provided by the hook.
validationMessages?ValidationMessages<SplitPaymentsFormRequiredValidation>Custom error text keyed by validation error code.

Also accepts description, formHookResult from RadioGroupHookFieldProps.


splits

One entry per bank account, each carrying a pre-bound Field component for the per-split amount.

{form.Fields.splits.map(entry => (
<entry.Field
key={entry.uuid}
label={entry.name ?? '…'}
validationMessages={{
REQUIRED: '…',
INVALID_AMOUNT: '…',
INVALID_PERCENTAGE: '…',
}}
/>
))}

SplitFieldEntry

Single per-account entry surfaced on form.Fields.splits. Each entry carries identifying metadata for the underlying bank account plus the bound Field component for its split amount.

PropertyTypeDescription
FieldComponentType<SplitFieldProps>Bound Field component for this split's amount input.
hiddenAccountNumberstring | nullLast-four masking string for the bank account number, when available.
namestring | nullDisplay name of the bank account, when available.
uuidstringBank account uuid that this split targets.

SplitFieldProps

Props accepted by a bound split-amount Field exposed on form.Fields.splits[i].Field. The Field is pre-bound to its split; it formats values as currency in Amount mode and as a percentage in Percentage mode. The remainder split is auto-disabled and treated as not required by the hook; the rest are required.

PropertyTypeDescription
labelstringLabel shown above the input.
description?ReactNodeOptional descriptive text rendered below the label.
FieldComponent?ComponentType<NumberInputProps>Override the rendered number input component.
formHookResult?FormHookResultPass-through of the parent form hook result for cross-field validation context.
max?string | numberForwarded to the underlying number input.
min?string | numberForwarded to the underlying number input.
placeholder?stringForwarded to the underlying number input.
validationMessages?ValidationMessages<SplitFieldValidation>Override the default localized validation message(s).

Validations

SplitPaymentsFormRequiredValidation

SplitPaymentsFormRequiredValidation = "REQUIRED"

Validation error codes emitted by useSplitPaymentsForm fields that only emit REQUIRED.

Utility types

SPLIT_BY_VALUES

const SPLIT_BY_VALUES: readonly ["Percentage", "Amount"]

Supported split-by modes: split by percentage of net pay, or by fixed dollar amount per account.


SplitByValue

SplitByValue = "Percentage" | "Amount"

Union of split-by mode values that the form accepts.


SplitFieldValidation

SplitFieldValidation = typeof SplitPaymentsFormErrorCodes.REQUIRED | typeof SplitPaymentsFormErrorCodes.INVALID_AMOUNT | typeof SplitPaymentsFormErrorCodes.INVALID_PERCENTAGE

Validation codes a bound split-amount Field can emit at submit time: REQUIRED (every non-remainder split must have a value), INVALID_AMOUNT (Amount mode, value < 0), INVALID_PERCENTAGE (Percentage mode, non-integer or out of 0..100). Supply translations for all three via validationMessages. The sum-to-100 invariant is surfaced separately via status.hasPercentageImbalance.


SplitPaymentsFormData

SplitPaymentsFormData = object

Shape of the values managed by the split payments form. splitAmount and priority are keyed by bank account uuid.

Properties

PropertyTypeDescription
priorityRecord<string, number>Per-account priority values keyed by bank account uuid; the highest priority receives the remainder.
splitAmountRecord<string, number | null>Per-account split values keyed by bank account uuid (percent or dollars depending on splitBy).
splitBySplitByValueSelected split mode — by percentage or by fixed amount.

SplitPaymentsFormErrorCode

SplitPaymentsFormErrorCode = "REQUIRED" | "INVALID_PERCENTAGE" | "INVALID_AMOUNT" | "DUPLICATE_PRIORITIES" | "PERCENTAGE_TOTAL_MISMATCH"

Union of validation error code strings emitted by the split payments form schema.


SplitPaymentsFormErrorCodes

const SplitPaymentsFormErrorCodes: object

Validation error codes emitted by the split payments form schema. Map these codes to localized copy in validationMessages when composing the hook.

Type Declaration

NameType
DUPLICATE_PRIORITIES"DUPLICATE_PRIORITIES"
INVALID_AMOUNT"INVALID_AMOUNT"
INVALID_PERCENTAGE"INVALID_PERCENTAGE"
PERCENTAGE_TOTAL_MISMATCH"PERCENTAGE_TOTAL_MISMATCH"
REQUIRED"REQUIRED"

SplitPaymentsFormField

SplitPaymentsFormField = "priority" | "splitBy" | "splitAmount"

Field names accepted by the split payments form.


SplitPaymentsFormFieldsMetadata

Per-field metadata exposed on form.fieldsMetadata for useSplitPaymentsForm.

Remarks

The three named fields are always present. In addition, one dynamic entry is keyed by full form path per split — splitAmount.<bankAccountUuid> — so the number and identity of those keys depend on the employee's bank accounts at runtime.

Indexable

[key: `splitAmount.${string}`]: FieldMetadata

Properties

PropertyTypeDescription
priorityFieldMetadataThe priority container field.
splitAmountFieldMetadataThe splitAmount container field. Per-split values live at splitAmount.<uuid>.
splitByFieldMetadataWithOptions<"Percentage" | "Amount">Split mode selector (by percentage or by fixed amount).

SplitPaymentsFormOptionalFieldsToRequire

SplitPaymentsFormOptionalFieldsToRequire = OptionalFieldsToRequire<typeof requiredFieldsConfig>

Keys of optional split payments fields that can be promoted to required via the hook's optionalFieldsToRequire option.


WorkingSplit

A single split entry — pairs a bank account identifier with its current split allocation.

Remarks

Surfaced on data.splits from useSplitPaymentsForm. Derived from paymentMethod.splits when present, otherwise from the employee's bank accounts (one entry per account, no allocated amount). Carries the raw domain data — use it for label construction or lookups by uuid.

Properties

PropertyTypeDescription
hiddenAccountNumberstring | nullMasked account number suffix, when available.
namestring | nullAccount nickname, when available.
prioritynumberOrdering value — splits are processed in ascending priority; the highest priority is the remainder.
splitAmountnumber | nullAllocation amount — null for the remainder split in Amount mode and for splits that haven't been allocated yet.
uuidstringUUID of the underlying bank account.

Endpoints