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
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.
| Property | Type | Description |
|---|---|---|
employeeId | string | Employee whose payment splits are being edited. |
optionalFieldsToRequire? | SplitPaymentsFormOptionalFieldsToRequire | Override optional fields to be required. Currently a no-op — splitBy and priority are always required, and per-split splitAmount required-ness is automatic. |
shouldFocusError? | boolean | Auto-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
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.
| Property | Type | Description |
|---|---|---|
actions | object | Actions 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[]) => void | Reorder 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). |
data | object | Server-fetched data and derived working values. |
data.bankAccounts | EmployeeBankAccount[] | All bank accounts available to allocate splits across. |
data.paymentMethod | EmployeePaymentMethod | The employee's current payment method. |
data.remainderId | string | UUID of the split that absorbs the remainder in Amount mode (always the last by priority). |
data.splits | WorkingSplit[] | The current working split entries, one per bank account. |
errorHandling | HookErrorHandling | Error state and recovery actions. |
form | object | Form bindings: pre-bound field components, per-field metadata, submission values, and react-hook-form internals. |
form.Fields | SplitPaymentsFormFields | - |
form.fieldsMetadata | SplitPaymentsFormFieldsMetadata | - |
form.getFormSubmissionValues | () => SplitPaymentsFormData | undefined | - |
form.hookFormInternals | HookFormInternals<SplitPaymentsFormData> | - |
isLoading | false | Always false in this branch; discriminates from HookLoadingResult. |
status | object | Submission state and reactive form-level flags. |
status.hasPercentageImbalance | boolean | true 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.isPending | boolean | true while the update mutation is in flight. |
status.mode | "update" | Always 'update' — the hook always edits an existing payment method. |
status.percentageTotal | number | Live 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.
| Property | Type | Description |
|---|---|---|
SplitBy | ComponentType<SplitByFieldProps> | Radio group bound to splitBy; selects Percentage or Amount split mode. |
splits | SplitFieldEntry[] | 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.
| Property | Type | Description |
|---|---|---|
label | string | Visible 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) => string | Maps 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.
| Property | Type | Description |
|---|---|---|
Field | ComponentType<SplitFieldProps> | Bound Field component for this split's amount input. |
hiddenAccountNumber | string | null | Last-four masking string for the bank account number, when available. |
name | string | null | Display name of the bank account, when available. |
uuid | string | Bank 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.
| Property | Type | Description |
|---|---|---|
label | string | Label shown above the input. |
description? | ReactNode | Optional descriptive text rendered below the label. |
FieldComponent? | ComponentType<NumberInputProps> | Override the rendered number input component. |
formHookResult? | FormHookResult | Pass-through of the parent form hook result for cross-field validation context. |
max? | string | number | Forwarded to the underlying number input. |
min? | string | number | Forwarded to the underlying number input. |
placeholder? | string | Forwarded 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
constSPLIT_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| typeofSplitPaymentsFormErrorCodes.INVALID_AMOUNT| typeofSplitPaymentsFormErrorCodes.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
| Property | Type | Description |
|---|---|---|
priority | Record<string, number> | Per-account priority values keyed by bank account uuid; the highest priority receives the remainder. |
splitAmount | Record<string, number | null> | Per-account split values keyed by bank account uuid (percent or dollars depending on splitBy). |
splitBy | SplitByValue | Selected 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
constSplitPaymentsFormErrorCodes: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
| Name | Type |
|---|---|
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
| Property | Type | Description |
|---|---|---|
priority | FieldMetadata | The priority container field. |
splitAmount | FieldMetadata | The splitAmount container field. Per-split values live at splitAmount.<uuid>. |
splitBy | FieldMetadataWithOptions<"Percentage" | "Amount"> | Split mode selector (by percentage or by fixed amount). |
SplitPaymentsFormOptionalFieldsToRequire
SplitPaymentsFormOptionalFieldsToRequire =
OptionalFieldsToRequire<typeofrequiredFieldsConfig>
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
| Property | Type | Description |
|---|---|---|
hiddenAccountNumber | string | null | Masked account number suffix, when available. |
name | string | null | Account nickname, when available. |
priority | number | Ordering value — splits are processed in ascending priority; the highest priority is the remainder. |
splitAmount | number | null | Allocation amount — null for the remainder split in Amount mode and for splits that haven't been allocated yet. |
uuid | string | UUID of the underlying bank account. |