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
{{ message }}
Repository navigation
[Due for payment 2026-10-01] Expense - Cursor appears briefly on list report field after clicking on it #101804
Version Number: 9.4.91-0 Reproducible in staging?: Yes Reproducible in production?: No If this was caught during regression testing, add the test name, ID and link from BrowserStack:#100735 Email or phone of affected tester (no customers):sjodjoijsonjoinj@gmail.com Issue reported by: Applause Internal Team Bug source: Exploratory - Significant User Experience Deterioration Device used: Mac 26.5 / Chrome App Component: Money Requests
Action Performed:
Precondition:
Create a list type report field
Go to staging.new.expensify.com
Go to workspace chat.
Create an expense.
Open the expense.
Click on the list report field.
Expected Result:
Cursor will not appear on list report field because it does not support text input.
Actual Result:
Cursor appears briefly on list report field after clicking on it.
👋 Friendly reminder that deploy blockers are time-sensitive ⏱ issues! Check out the open `StagingDeployCash` deploy checklist to see the list of PRs included in this release, then work quickly to do one of the following:
Identify the pull request that introduced this issue and revert it.
The regression is a one-prop omission in brand-new code (a list report field now renders a real web <input> that gets programmatically focused on press, with nothing hiding the caret), so a targeted fix is far smaller and safer than reverting a large, multi-file feature that also landed a shared useSaveReportField hook and DatePicker/EditReportFieldDropdown changes.
Suggested fix — in ReportFieldInlineInput.tsx LIST branch, add caretHidden to the trigger TextInput. caretHidden maps to caret-color: transparent in react-native-web and is applied after inputStyle, so it cannot be overridden by the existing pointerEventsNone input style. Optionally also readOnly so the field can never receive typed input, and/or mirror the DatePicker approach of blurring the input when the popover opens.
Assigned: @Gonals and @daledah (approving reviewers of the causing PR) — already assigned by Melvin; the PR author is @MelvinBot (bot), so there is no human author to add. Labels: No changes. DeployBlockerCash stays because an App PR caused this and the fix is in Expensify/App. No DeployBlocker label is present, so nothing was removed.
Before #100735, a report field in the expense/report view was rendered as a MenuItemWithTopDescription row that navigated to the report field editor page. A menu item contains no text input at all, so a caret was structurally impossible there.
gh pr view 100735 --json files confirms ReportFieldInlineInput.tsx is added by this PR and that MoneyRequestViewReportFields.tsx / MoneyReportView.tsx are modified by it.
Root Cause
For a list field, ReportFieldInlineInput renders a TextInput as the dropdown trigger with role={CONST.ROLE.COMBOBOX}, inputStyle={styles.pointerEventsNone} and disableKeyboard, and onPress={onPress} from FilterPopupButton.
Three things combine on web:
BaseTextInput's press handler calls inputProps.onPress?.(event) and then, when the event's default was not prevented, input.current?.focus(). So the real DOM <input> is focused on click. inputStyle={styles.pointerEventsNone} only stops the mouse from reaching the input; it does not stop this programmatic focus.
disableKeyboard on web only sets inputmode="none" (it suppresses the mobile virtual keyboard). It does not set readOnly and it does not hide the caret, so a focused desktop <input> blinks a caret.
FilterPopupButton.calculatePopoverPositionAndToggleOverlay opens the popover asynchronously (KeyboardUtils.dismissKeyboardAndExecute → calculatePopoverPosition(...).then(...)), and unlike DatePicker — which calls textInputRef.current?.blur() as the first thing in showDatePickerModal — this branch never blurs the trigger. The caret is therefore visible for the window between the click and the popover mounting and taking focus, which is exactly the reported "appears briefly".
The value is controlled and there is no onChangeText on this input, so nothing can actually be typed into the field — the impact is purely the visible caret.
💡 Suggested AI code review rule
This looks like a recurring, mechanically detectable pattern (any TextInput used purely as a press-to-open trigger has it), so it may be worth a coding-standards rule so the AI reviewer catches the next one. Proposed for Expensify/App (.claude/skills/app-coding-standards):
Rule:UI-4 — A TextInput used as a press-to-open trigger must hide its caret
Condition: When a TextInput is rendered as a non-typable trigger (it has onPress/disableKeyboard, role={CONST.ROLE.COMBOBOX}, or an inputStyle of pointerEventsNone and no onChangeText), it must also set caretHidden (and normally readOnly), or blur the input when the overlay opens. Do not rely on disableKeyboard or pointerEventsNone — on web the former only sets inputmode="none" and the latter does not prevent BaseTextInput from programmatically focusing the input on press.
Search pattern: JSX <TextInput ... /> elements that have disableKeyboard or onPress= or role={CONST.ROLE.COMBOBOX} and no onChangeText, and that do not also pass caretHidden — e.g. rg -U '<TextInput[^>]*(disableKeyboard|ROLE\.COMBOBOX)' src/ --multiline then filter out matches containing caretHidden.
The full rule file, with the ❌/✅ code inline in the App app-coding-standards format, would go in Expensify/App itself. If it's worth adding, a maintainer can open it there as a draft PR.
changed the title [-]Expense - Cursor appears briefly on list report field after clicking on it[/-][+][Due for payment 2026-10-01] Expense - Cursor appears briefly on list report field after clicking on it[/+]on Sep 24, 2026
The solution for this issue has been 🚀 deployed to production 🚀 in version 9.4.92-8 and is now subject to a 7-day regression period 📆. Here is the list of pull requests that resolve this issue:
If no regressions arise, payment will be issued on 2026-10-01. 🎊
The following checklist (instructions) will need to be completed before the issue can be closed. Please copy/paste the Contributor+ Checklist from here into a new comment on this GH and complete it. If you have the K2 extension, you can simply click: [this button]. If no checklist is needed for this issue, you can click: [no checklist button]
Activity
applause-bot commentedon Sep 21, 2026
While Applause doesn't embed attachments for this bug, here are the links for quick view:
https://platform.applause.com/services/links/v1/external/f9d9348972ae0817ba16a9890a7dcc2dc9bc2118069e07e52231c9b6131c2190
melvin-bot commentedon Sep 21, 2026
You have been assigned to this deploy blocker because you recently merged this PR: #100735
github-actions commentedon Sep 21, 2026
👋 Friendly reminder that deploy blockers are time-sensitive ⏱ issues! Check out the open `StagingDeployCash` deploy checklist to see the list of PRs included in this release, then work quickly to do one of the following:
melvin-bot commentedon Sep 21, 2026
@Gonals @daledah you have been assigned to this deploy blocker because you reviewed the offending PR: #100735
melvin-bot commentedon Sep 21, 2026
💬 A slack conversation has been started in #expensify-open-source
MelvinBot commentedon Sep 21, 2026
🔍 Investigation Summary
Classification: Frontend bug
Causing PR: #100735 - "Show up to three report fields per row and edit them inline" by @MelvinBot (High confidence)
Related Issues: [$250] Report fields should be shown in a grid and editable inline (the issue the PR implements)
Recommendation: ROLL FORWARD
The regression is a one-prop omission in brand-new code (a list report field now renders a real web
<input>that gets programmatically focused on press, with nothing hiding the caret), so a targeted fix is far smaller and safer than reverting a large, multi-file feature that also landed a shareduseSaveReportFieldhook andDatePicker/EditReportFieldDropdownchanges.Suggested fix — in
ReportFieldInlineInput.tsxLIST branch, addcaretHiddento the triggerTextInput.caretHiddenmaps tocaret-color: transparentin react-native-web and is applied afterinputStyle, so it cannot be overridden by the existingpointerEventsNoneinput style. Optionally alsoreadOnlyso the field can never receive typed input, and/or mirror theDatePickerapproach of blurring the input when the popover opens.Assigned: @Gonals and @daledah (approving reviewers of the causing PR) — already assigned by Melvin; the PR author is @MelvinBot (bot), so there is no human author to add.
Labels: No changes.
DeployBlockerCashstays because an App PR caused this and the fix is inExpensify/App. NoDeployBlockerlabel is present, so nothing was removed.📋 Detailed Analysis
Evidence
9.4.91-0, not on production — consistent with something in the current Deploy Checklist: New Expensify 2026-09-21.MenuItemWithTopDescriptionrow that navigated to the report field editor page. A menu item contains no text input at all, so a caret was structurally impossible there.MenuItemWithTopDescriptionfrom bothMoneyRequestViewReportFields.tsxandMoneyReportView.tsxand replaces them with the newReportFieldInlineInput, which renders a realTextInputforlist-type fields.9.4.91-0; the bug was reported against that same build.Verification
Affected files (all at merge commit
44bd04c):src/components/MoneyRequestReportView/ReportFieldInlineInput.tsx#L199-L223— new in this PR, renders the list field as aTextInputtrigger forFilterPopupButton.src/components/TextInput/index.tsx#L29-L31— on web,disableKeyboardonly setsinputmode="none".src/components/TextInput/BaseTextInput/implementation/index.tsx#L224-L234— the press handler focuses the underlying input.gh pr view 100735 --json filesconfirmsReportFieldInlineInput.tsxis added by this PR and thatMoneyRequestViewReportFields.tsx/MoneyReportView.tsxare modified by it.Root Cause
For a
listfield,ReportFieldInlineInputrenders aTextInputas the dropdown trigger withrole={CONST.ROLE.COMBOBOX},inputStyle={styles.pointerEventsNone}anddisableKeyboard, andonPress={onPress}fromFilterPopupButton.Three things combine on web:
BaseTextInput's press handler callsinputProps.onPress?.(event)and then, when the event's default was not prevented,input.current?.focus(). So the real DOM<input>is focused on click.inputStyle={styles.pointerEventsNone}only stops the mouse from reaching the input; it does not stop this programmatic focus.disableKeyboardon web only setsinputmode="none"(it suppresses the mobile virtual keyboard). It does not setreadOnlyand it does not hide the caret, so a focused desktop<input>blinks a caret.FilterPopupButton.calculatePopoverPositionAndToggleOverlayopens the popover asynchronously (KeyboardUtils.dismissKeyboardAndExecute→calculatePopoverPosition(...).then(...)), and unlikeDatePicker— which callstextInputRef.current?.blur()as the first thing inshowDatePickerModal— this branch never blurs the trigger. The caret is therefore visible for the window between the click and the popover mounting and taking focus, which is exactly the reported "appears briefly".The value is controlled and there is no
onChangeTexton this input, so nothing can actually be typed into the field — the impact is purely the visible caret.💡 Suggested AI code review rule
This looks like a recurring, mechanically detectable pattern (any
TextInputused purely as a press-to-open trigger has it), so it may be worth a coding-standards rule so the AI reviewer catches the next one. Proposed forExpensify/App(.claude/skills/app-coding-standards):UI-4— ATextInputused as a press-to-open trigger must hide its caretTextInputis rendered as a non-typable trigger (it hasonPress/disableKeyboard,role={CONST.ROLE.COMBOBOX}, or aninputStyleofpointerEventsNoneand noonChangeText), it must also setcaretHidden(and normallyreadOnly), or blur the input when the overlay opens. Do not rely ondisableKeyboardorpointerEventsNone— on web the former only setsinputmode="none"and the latter does not preventBaseTextInputfrom programmatically focusing the input on press.BaseTextInput's press handler focuses the real DOM<input>, so a field that accepts no text still shows a blinking caret until the popover steals focus. That shipped as deploy blocker Expense - Cursor appears briefly on list report field after clicking on it.<TextInput ... />elements that havedisableKeyboardoronPress=orrole={CONST.ROLE.COMBOBOX}and noonChangeText, and that do not also passcaretHidden— e.g.rg -U '<TextInput[^>]*(disableKeyboard|ROLE\.COMBOBOX)' src/ --multilinethen filter out matches containingcaretHidden.ReportFieldInlineInput.tsx#L203-L220caretHiddento that sameTextInput; the existing blur-on-open precedent isDatePicker/index.tsx#L117-L121The full rule file, with the ❌/✅ code inline in the App
app-coding-standardsformat, would go inExpensify/Appitself. If it's worth adding, a maintainer can open it there as a draft PR.melvin-bot commentedon Sep 21, 2026
If you are the assigned CME please investigate whether the linked PR caused a regression and leave a comment with the results.
If a regression has occurred and you are the assigned CM follow the instructions here.
If this regression could have been avoided please consider also proposing a recommendation to the PR checklist so that we can avoid it in the future.
melvin-bot commentedon Sep 21, 2026
If you are the assigned CME please investigate whether the linked PR caused a regression and leave a comment with the results.
If a regression has occurred and you are the assigned CM follow the instructions here.
If this regression could have been avoided please consider also proposing a recommendation to the PR checklist so that we can avoid it in the future.
melvin-bot commentedon Sep 22, 2026
If you are the assigned CME please investigate whether the linked PR caused a regression and leave a comment with the results.
If a regression has occurred and you are the assigned CM follow the instructions here.
If this regression could have been avoided please consider also proposing a recommendation to the PR checklist so that we can avoid it in the future.
Gonals commentedon Sep 22, 2026
PR Reverted
IuliiaHerets commentedon Sep 22, 2026
Chrome / v9.4.91-1
We see old UI, no issue anymore
bandicam.2026-09-22.13-27-26-749.mp4
[-]Expense - Cursor appears briefly on list report field after clicking on it[/-][+][Due for payment 2026-10-01] Expense - Cursor appears briefly on list report field after clicking on it[/+]melvin-bot commentedon Sep 24, 2026
@daledah
The solution for this issue has been 🚀 deployed to production 🚀 in version 9.4.92-8 and is now subject to a 7-day regression period 📆. Here is the list of pull requests that resolve this issue:
If no regressions arise, payment will be issued on 2026-10-01. 🎊
The following checklist (instructions) will need to be completed before the issue can be closed. Please copy/paste the Contributor+ Checklist from here into a new comment on this GH and complete it. If you have the K2 extension, you can simply click: [this button]. If no checklist is needed for this issue, you can click: [no checklist button]