You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
As discussed in this issue and this Slack thread we should replace modal screens (navigation screens/routes, that only render a modal) and modals that stay open when the containing screen gets unmounted.
The current modals use react-native-modal which uses RN internal Modal under the hood. Using these modals with @react-navigation/native-stack poses issues with animations and navigation, as these modals cannot animate in/out, due to the screen mounting/unmounting at the same time. Additionally, the animations will not look the same as the rest of the screen animations, which doesn't look very nice.
Solution
Replace the following types of modals with modal (screens) from @react-navigation
screens/routes that only render a modal
modals on screens, that are navigated back from while the modal is still open or animating out at the same time
List of components and screens to migrate to @react-navigation modal screens
Tracking my progress on an exhaustive list of components and screens that can/should be migrated to modal screens.
The list of components/screens (and other files) are triaged/prioritized as follows:
(File names are listed without file ending, usually .tsx)
🔴 HIGH: Should definitely be migrated, due to current issues with animations and navigation.
These modals are already causing issues with animations, because
they are animating in while a new screen is still mounting
they are still open/displayed while the old screen unmounting
causing no or cut off animations.
🟡 MEDIUM: Not causing any issues at the moment, but still worth to migrate to modal screens since the behave "like a screen", to achieve consistent animations and generally improve navigation. (gestures, native feel)
This includes modals that are either
animated in from right-to-left (like a screen) or
that are part of another screen with animation: none,
etc.
🟢 LOW: These screens are animated in from bottom-to-top like actual modals and are never (un-)mounted while at the same time as the screen. Migrating these modals to modal screens (and extra navigation routes) would make animations more consistent with the other screens, but it is not necessary and might not be worth the effort.
Using a custom modal implementation or something like gorhom/react-native-bottom-sheet probably makes more sense.
Base components to (potentially) re-write
BaseModal
Affected modals:
TransactionStartDateSelectorModal
PaymentCardCurrencyModal
AmountSelectorModal
AttachmentModal
AvatarCropModal
CategorySelectorModal
ConfirmModal
CountrySelectorModal
YearPickerModal
DecisionModal
FeatureTrainingModal
PushRowModal
RequireTwoFactorAuthenticationModal
SearchRouterModal
StateSelectorModal
TestToolsModal
TextSelectorModal
ValueSelectorModal
BusinessTypeSelectorModal
NetSuiteCustomListSelectorModal
ExpenseLimitTypeSelectorModal
TransactionStartDateSelectorModal
UnitSelectorModal
WorkspaceMemberDetailsRoleSelectionModal
InitialListValueSelectorModal
TypeSelectorModal
Pages:
EditReportFieldDate
SetDatePage
DateOfBirthPage
SearchSelectedNarrow
Components:
SearchDateFilterBase
DateOfBirthStep
DebugDetailsDateTimePickerPage
AdditionalDetailsStep
IncorporationDateBusiness
IOURequestStepDate
Popover (uses Modal)
Comment: Uses Modal under the hood
Components:
EmojiPicker
PopoverMenu
PopoverWithMeasuredContent
PopoverReportActionContextMenu
BasePopoverReactionList
ProcessMoneyReportHoldMenu
WorkspaceCardsListLabel
AccountSwitcher
AddPaymentMethodMenu
AvatarWithImagePicker
AttachmentPickerWithMenu
Triaging
Modals only visible on native platforms (Android & iOS) are marked with 📱.
🔴 HIGH: Modals causing issues at the moment
Modals animating in from the bottom are marked with ⬆️, modals animating in from the right with ⬅️
AttachmentModal ⬅️ (screen recordings attached)
Comment: Add one or many extra routes?
Components:
AvatarWithImagePicker
ReportAvatar
TransactionReceiptPage
ReportActionCompose
ReportAttachments
ProfileAvatar
WorkspaceAvatar
iOS: Animating in not working, because the modal is animating at the same time, as a new screen with animation: none is mounting.
P/S Slack thread: expensify.slack.com/archives/C01GTK53T8Q/p1733938583809829
Problem
As discussed in this issue and this Slack thread we should replace modal screens (navigation screens/routes, that only render a modal) and modals that stay open when the containing screen gets unmounted.
The current modals use
react-native-modalwhich uses RN internal Modal under the hood. Using these modals with@react-navigation/native-stackposes issues with animations and navigation, as these modals cannot animate in/out, due to the screen mounting/unmounting at the same time. Additionally, the animations will not look the same as the rest of the screen animations, which doesn't look very nice.Solution
Replace the following types of modals with modal (screens) from
@react-navigationcc @mountiny
List of components and screens to migrate to
@react-navigationmodal screensTracking my progress on an exhaustive list of components and screens that can/should be migrated to modal screens.
The list of components/screens (and other files) are triaged/prioritized as follows:
(File names are listed without file ending, usually
.tsx)🔴 HIGH: Should definitely be migrated, due to current issues with animations and navigation.
These modals are already causing issues with animations, because
causing no or cut off animations.
🟡 MEDIUM: Not causing any issues at the moment, but still worth to migrate to modal screens since the behave "like a screen", to achieve consistent animations and generally improve navigation. (gestures, native feel)
This includes modals that are either
animation: none,🟢 LOW: These screens are animated in from bottom-to-top like actual modals and are never (un-)mounted while at the same time as the screen. Migrating these modals to modal screens (and extra navigation routes) would make animations more consistent with the other screens, but it is not necessary and might not be worth the effort.
Using a custom modal implementation or something like
gorhom/react-native-bottom-sheetprobably makes more sense.Base components to (potentially) re-write
BaseModal
TransactionStartDateSelectorModalPaymentCardCurrencyModalAmountSelectorModalAttachmentModalAvatarCropModalCategorySelectorModalConfirmModalCountrySelectorModalYearPickerModalDecisionModalFeatureTrainingModalPushRowModalRequireTwoFactorAuthenticationModalSearchRouterModalStateSelectorModalTestToolsModalTextSelectorModalValueSelectorModalBusinessTypeSelectorModalNetSuiteCustomListSelectorModalExpenseLimitTypeSelectorModalTransactionStartDateSelectorModalUnitSelectorModalWorkspaceMemberDetailsRoleSelectionModalInitialListValueSelectorModalTypeSelectorModalEditReportFieldDateSetDatePageDateOfBirthPageSearchSelectedNarrowSearchDateFilterBaseDateOfBirthStepDebugDetailsDateTimePickerPageAdditionalDetailsStepIncorporationDateBusinessIOURequestStepDatePopover (uses Modal)
Modalunder the hoodEmojiPickerPopoverMenuPopoverWithMeasuredContentPopoverReportActionContextMenuBasePopoverReactionListProcessMoneyReportHoldMenuWorkspaceCardsListLabelAccountSwitcherAddPaymentMethodMenuAvatarWithImagePickerAttachmentPickerWithMenuTriaging
Modals only visible on native platforms (Android & iOS) are marked with 📱.
🔴 HIGH: Modals causing issues at the moment
Modals animating in from the bottom are marked with ⬆️, modals animating in from the right with ⬅️
AttachmentModal ⬅️ (screen recordings attached)
Comment: Add one or many extra routes?
Components:
AvatarWithImagePickerReportAvatarTransactionReceiptPageReportActionComposeReportAttachmentsProfileAvatarWorkspaceAvatariOS: Animating in not working, because the modal is animating at the same time, as a new screen with
animation: noneis mounting.Simulator.Screen.Recording.-.iPhone.16.Pro.-.2025-01-05.at.14.21.11.mp4
Android: Animation out is not working, probably due to the screen unmounting before the modal can animate out
Screen.Recording.2025-01-05.at.14.20.52.mov
ConfirmModal ⬆️ (screen recordings attached)
Comment: Not all
ConfirmModals are causing issuesScreens, where we navigate back while also animating the modal out:
TagSettingsPage(Remove tag)WorkspaceEditTaxPage(Remove tax)CategorySettingsPage(Remove category)PolicyDistanceRateDetailsPage(Remove distance rate)iOS: Modal not able to animate out, because the screen that wraps the modal is already unmounting:
Simulator.Screen.Recording.-.iPhone.16.Pro.-.2025-01-05.at.14.24.29.mp4
Android: Same issue, though less obvious:
Screen.Recording.2025-01-05.at.14.24.47.mov
🟡 MEDIUM: Screen-like modals - Animating in from right-to-left
SearchRouterModal
AuthScreensAmountSelectorModal -> AmountPicker
FormWorkspaceCreateTaxPageAvatarCropModal -> AvatarWithImagePicker
NewChatConfirmPageReportDetailsPageProfilePageWorkspaceProfilePageCategorySelectorModal
WorkspaceCategoriesSettingsPageCategorySelectorPolicyDistanceRatesSettingsPageWorkspacePerDiemSettingsPage(unused?)YearPickerModal -> CalendarPicker -> DatePicker
SearchDateFilterBaseDateOfBirthStepDebugDetailsDateTimePickerPageEditReportFieldDateAdditionalDetailsStepIncorporationDateBusinessIOURequestStepDateSetDatePageDateOfBirthPageTransactionStartDateSelectorModalTextSelectorModal -> TextPicker
CreateReportFieldsPageWorkspaceCreateTaxPageFormValidateCodeActionModal
MissingPersonalDetailsContent(multiple occurrences)BankAccountStepContactMethodDetailsPage(multiple occurrences)NewContactMethodPageDelegateMagicCodeModalCodesStepBaseGetPhysicalCardExpensifyCardPageReportCardLostPageReportVirtualCardFraudPageVerifyAccountPageConfirmationStepValueSelectorModal -> ValuePicker
WorkspaceNewRoomPageForm(multiple occurrences)FeatureTrainingModal
TrackTrainingPageExplanationModalMigratedUserWelcomeModalOnboardingWelcomeVideoPaymentCardCurrencyModal
ConnectToQuickbooksOnlineFlow 📱
ConnectToXeroFlow 📱
CardAuthenticationModal
PaymentCardWorkspaceOwnerChangeWrapperPageNetSuiteCustomListSelectorModal -> NetSuiteCustomListPicker
ChooseCustomListStepExpenseLimitTypeSelectorModal -> ExpenseLimitTypeSelector
CategoryFlagAmountsOverPageTransactionStartDateSelectorModal
TransactionStartDateStepUnitSelectorModal -> UnitSelector
PolicyDistanceRatesSettingsPageWorkspaceMemberDetailsRoleSelectionModal
WorkspaceMemberDetailsPage(multiple occurrences)InitialListValueSelectorModal -> InitialListValueSelector
CreateReportFieldsPageTypeSelectorModal -> TypeSelector
CreateReportFieldsPage🟢 LOW: Contained modals - Only visible as part of the current screen, animating in from bottom-to-top
ConfirmModal
EditReportFieldPageReportDetailsPageReportParticipantDetailsPageReportParticipantsPageRoomMemberDetailsPageRoomMembersPageEmptySearchViewConsolePageInitialSettingsPageContactMethodDetailsPageVisibilityPageCloseAccountPageSecuritySettingsPageTroubleshootPageWalletPageWorkspaceInitialPageWorkspaceMembersPageWorkspaceMoreFeaturesPageWorkspaceProfilePageWorkspacesListPagePolicyAccountingPageSageIntacctEditUserDimensionsPageNetSuiteImportCustomFieldViewImportedCategoriesPageWorkspaceCategoriesPageWorkspaceCompanyCardDetailsPageWorkspaceCompanyCardsSettingsPagePolicyDistanceRatesPageWorkspaceEditCardLimitPageWorkspaceEditCardLimitTypePageWorkspaceExpensifyCardDetailsPageWorkspaceExpensifyCardPageEmptyStateWorkspaceInvoiceVBASectionImportedMembersPageWorkspaceMemberDetailsPageImportedPerDiemPageWorkspacePerDiemDetailsPageWorkspacePerDiemPageReportFieldsListValuesPageReportFieldsSettingsPageReportFieldsValueSettingsPageWorkspaceReportFieldsPageImportedTagsPageWorkspaceTagsPageWorkspaceViewTagsPageWorkspaceTaxesPageWorkspaceWorkflowsPageWorkspaceWorkflowsApprovalsEditPageExpensifyAccountSwitcherAccountingConnectionConfirmationModalAttachmentModalConfirmModalDelegateNoAccessModalFocusModeNotificationImportSpreadsheetLocationPermissionModalMoneyReportHeaderExportWithDropdownMenuSearchPageHeaderSupportActionRestrictedModalBaseUpdateAppModalHeaderViewPopoverReportActionContextMenuReportDetailsExportPageFloatingActionButtonAndPopoverIOURequestStepScanIOURequestStepWaypointCardSectionWorkspaceResetBankAccountModaluseDeleteSavedSearchDecisionModal
SearchPageHeaderReportDetailsPage(multiple occurrences)WorkspaceMembersPage(multiple occurrences)WorkspaceCategoriesPage(multiple occurrences)WorkspaceTagsPageBaseImportOnyxStateProcessMoneyReportHoldMenuSelectionListModal -> SelectionListWithModal
SearchReportParticipantsPageRoomMembersPageWorkspaceMembersPageWorkspaceCategoriesPagePolicyDistanceRatesPageWorkspacePerDiemPageReportFieldsListValuesPageWorkspaceReportFieldsPageWorkspaceTagsPageWorkspaceViewTagsPageWorkspaceTaxesPageRequireTwoFactorAuthenticationModal
Expensify(multiple occurrences)TestToolsModal
AuthScreensSearchSelectedNarrow -> SearchPageHeader
SearchPageSearchSelectionModaHeader❓ Unknown: Unable to test because the modal is either missing or not accessible
CountrySelectorModal -> CountryPicker -> Address
MissingPersonalDetailsContent->MissingPersonalDetails(unused?)StateSelectorModal -> StatePicker -> Address
MissingPersonalDetailsContent->MissingPersonalDetails(unused?)PushRowModal -> PushRowWithModal (unused?)
ReimburseAccountPageAddressFormFieldsBusinessTypeIncorporationLocationPaymentVolumeConfirmationBusinessTypeSelectorModal -> BusinessTypePicker
ReimburseAccountPageBusinessInfoIssue Owner
Current Issue Owner: @mountiny