What problem does it solve?
Inconsistent placement and behavior of Save Changes controls leads to user confusion, accidental navigation away from unsaved edits, and duplicated or missing submission flows; this guidance defines a single SaveButton API, placement patterns, dirty-tracking flow, and dialog exceptions to eliminate those issues.
Core Features & Use Cases
- Standardized SaveButton component contract with props for onClick, isPending, hasChanges, disabled, type, size, and test identifier to ensure consistent behavior and testability.
- Three placement patterns: PageHeader actions for primary saves, bottom-of-form mirrors paired with PageHeader saves for long forms, and tab/section-level saves for isolated sections, with examples referenced for each pattern.
- Dirty-tracking flow using a local draft state compared to last-saved data, an isDirty / hasChanges flag, a beforeunload navigation warning, and mutation handling via TanStack Query to manage isPending and reset state on success.
- Dialog exception that uses standard DialogFooter buttons rather than the SaveButton to accommodate modal UX constraints.
- Practical examples include property edit pages, company assumptions pages, and admin settings tabs where each pattern and the dirty-tracking flow are demonstrated.
Quick Start
Place the SaveButton in the PageHeader actions, maintain a local draft and isDirty flag passed to hasChanges, and trigger a TanStack Query mutation while passing mutation.isPending to isPending.