Skip to content

useFormStatus

Subscribes to a form's reactive status signals, returning plain values that trigger re-renders only when they change.

Import

ts
import { useFormStatus } from '@ereo/forms'

Signature

ts
function useFormStatus(form: FormStoreInterface<any>): {
  isSubmitting: boolean;
  submitState: FormSubmitState;
  isValid: boolean;
  isDirty: boolean;
  submitCount: number;
}

Parameters

NameTypeDescription
formFormStoreInterface<any>The form store (from useForm or createFormStore)

Returns

NameTypeDescription
isSubmittingbooleantrue while the form is submitting
submitStateFormSubmitStateCurrent submit lifecycle state
isValidbooleantrue when no errors exist on any field or the form itself
isDirtybooleantrue when any field value differs from the baseline
submitCountnumberNumber of successful submissions

FormSubmitState

ts
type FormSubmitState = 'idle' | 'submitting' | 'success' | 'error'
ValueDescription
'idle'No submit has been attempted, or the form was reset
'submitting'Submit is in progress
'success'Last submit completed successfully
'error'Last submit failed (validation or handler error)

Examples

Submit Button State

tsx
import { useFormStatus } from '@ereo/forms'

function SubmitButton({ form }) {
  const { isSubmitting, isValid } = useFormStatus(form)

  return (
    <button type="submit" disabled={isSubmitting || !isValid}>
      {isSubmitting ? 'Saving...' : 'Save'}
    </button>
  )
}

Status Banner

tsx
function FormStatusBanner({ form }) {
  const { submitState } = useFormStatus(form)

  if (submitState === 'success') {
    return <div className="success">Saved successfully.</div>
  }
  if (submitState === 'error') {
    return <div className="error">Something went wrong. Please try again.</div>
  }
  return null
}

Unsaved Changes Warning

tsx
import { useEffect } from 'react'

function UnsavedChangesGuard({ form }) {
  const { isDirty } = useFormStatus(form)

  useEffect(() => {
    const handler = (e: BeforeUnloadEvent) => {
      if (isDirty) {
        e.preventDefault()
        e.returnValue = ''
      }
    }
    window.addEventListener('beforeunload', handler)
    return () => window.removeEventListener('beforeunload', handler)
  }, [isDirty])

  return null
}

How It Works

Each status value comes from a Signal instance on the form store. useFormStatus reads them via useSignal() from @ereo/state, which uses useSyncExternalStore internally. This means the component re-renders only when the specific signal value changes -- not on every form change.

Released under the MIT License.