Custom report fields allow you to capture additional information on expense reports beyond the standard fields. This guide explains how to create, edit, and manage report fields.
Understanding Report Fields
Report fields are custom data points that can be added to expense reports. They help capture organization-specific information needed for accounting, compliance, or reporting purposes.
Field Types
New Expensify supports several types of report fields:
Text Fields Free-form text input for alphanumeric data
Dropdown Lists Predefined list of options to choose from
Date Fields Date picker for capturing dates
Formula Fields Calculated fields based on other field values
Editing Report Fields
Field Editor Page
The Edit Report Field page provides a unified interface for editing all field types:
// From src/pages/EditReportFieldPage.tsx
function EditReportFieldPage ({ route } : EditReportFieldPageProps ) {
const { backTo , reportID , policyID } = route . params ;
const fieldKey = getReportFieldKey ( route . params . fieldID );
const [ report ] = useOnyx ( ` ${ ONYXKEYS . COLLECTION . REPORT }${ reportID } ` );
const [ policy ] = useOnyx ( ` ${ ONYXKEYS . COLLECTION . POLICY }${ policyID } ` );
const [ recentlyUsedReportFields ] = useOnyx ( ONYXKEYS . RECENTLY_USED_REPORT_FIELDS );
const isTitleField = route . params . fieldID === CONST . REPORT_FIELD_TITLE_FIELD_ID ;
let reportField = report ?. fieldList ?.[ fieldKey ] ?? policy ?. fieldList ?.[ fieldKey ];
let policyField = policy ?. fieldList ?.[ fieldKey ] ?? reportField ;
// If the title field is missing, use fallback so that it can still be edited and matches the OldDot behavior.
if ( isTitleField && ! reportField && ! policyField ) {
const fallbackTitleField = getTitleFieldWithFallback ( policy );
reportField = fallbackTitleField ;
policyField = fallbackTitleField ;
}
const isDisabled = isReportFieldDisabledForUser ( report , reportField , policy ) && reportField ?. type !== CONST . REPORT_FIELD_TYPES . FORMULA ;
// ... field editing logic
}
Field Validation
Fields are validated before submission:
// From src/pages/EditReportFieldText.tsx
const validate = useCallback (
( values : FormOnyxValues < typeof ONYXKEYS . FORMS . REPORT_FIELDS_EDIT_FORM >) => {
const errors : FormInputErrors < typeof ONYXKEYS . FORMS . REPORT_FIELDS_EDIT_FORM > = {};
const inputValue = values [ fieldKey ]. trim ();
if ( isRequired && inputValue === '' ) {
errors [ fieldKey ] = translate ( 'common.error.fieldRequired' );
}
if ( hasCircularReferences ( inputValue , fieldName , fieldList )) {
errors [ fieldKey ] = translate ( 'workspace.reportFields.circularReferenceError' );
}
return errors ;
},
[ fieldName , fieldKey , isRequired , translate , fieldList ],
);
Text Fields
Editing Text Fields
Text fields provide a simple input for alphanumeric data:
// From src/pages/EditReportFieldText.tsx
function EditReportFieldTextPage ({ fieldName , onSubmit , fieldValue , isRequired , fieldKey , fieldList , disabled = false } : EditReportFieldTextPageProps ) {
const styles = useThemeStyles ();
const { translate } = useLocalize ();
const { inputCallbackRef } = useAutoFocusInput ();
const reportFieldName = Str . UCFirst ( fieldName );
return (
< FormProvider
style = { [ styles . flexGrow1 , styles . ph5 ] }
formID = { ONYXKEYS . FORMS . REPORT_FIELDS_EDIT_FORM }
onSubmit = { onSubmit }
validate = { validate }
submitButtonText = { translate ( 'common.save' ) }
isSubmitButtonVisible = { ! disabled }
enabledWhenOffline
shouldHideFixErrorsAlert
>
< View style = { styles . mb4 } >
< InputWrapper
InputComponent = { TextInput }
inputID = { fieldKey }
name = { fieldKey }
defaultValue = { fieldValue }
label = { reportFieldName }
accessibilityLabel = { reportFieldName }
role = { CONST . ROLE . PRESENTATION }
ref = { inputCallbackRef }
disabled = { disabled }
/>
</ View >
</ FormProvider >
);
}
Circular Reference Detection
Formula fields are checked for circular references:
// From src/pages/EditReportFieldText.tsx
if ( hasCircularReferences ( inputValue , fieldName , fieldList )) {
errors [ fieldKey ] = translate ( 'workspace.reportFields.circularReferenceError' );
}
Circular References Be careful when creating formula fields that reference other fields. Circular references (Field A references Field B, which references Field A) will cause validation errors.
Dropdown Fields
Editing Dropdown Fields
Dropdown fields provide a list of predefined options:
// From src/pages/EditReportFieldPage.tsx
{ reportField . type === CONST . REPORT_FIELD_TYPES . LIST && (
< EditReportFieldDropdown
fieldKey = { fieldKey }
fieldValue = { fieldValue }
fieldOptions = { policyField . values . filter (( _value : string , index : number ) => ! policyField . disabledOptions . at ( index )) }
onSubmit = { handleReportFieldChange }
/>
)}
Only enabled options are displayed to users. Disabled options are filtered out from the selection list.
Date Fields
Editing Date Fields
Date fields use a date picker for easy date selection:
// From src/pages/EditReportFieldPage.tsx
{ reportField . type === CONST . REPORT_FIELD_TYPES . DATE && (
< EditReportFieldDate
fieldName = { Str . UCFirst ( reportField . name ) }
fieldKey = { fieldKey }
fieldValue = { fieldValue }
isRequired = { ! reportField . deletable }
onSubmit = { handleReportFieldChange }
/>
)}
Formula fields are calculated automatically and displayed as read-only:
// From src/pages/EditReportFieldPage.tsx
{ reportField . type === CONST . REPORT_FIELD_TYPES . FORMULA && ! isReportFieldTitle && (
< EditReportFieldText
fieldName = { reportField . name }
fieldKey = { fieldKey }
fieldValue = { fieldValue }
isRequired = { ! isReportFieldDeletable }
onSubmit = { handleReportFieldChange }
fieldList = { policy ?. fieldList }
disabled
/>
)}
Formula fields cannot be edited directly. They are automatically calculated based on the formula definition and values of other fields.
Updating Report Fields
Field Update Logic
When a report field is updated, the system performs validation and syncs with the server:
// From src/pages/EditReportFieldPage.tsx
const handleReportFieldChange = ( form : FormOnyxValues < typeof ONYXKEYS . FORMS . REPORT_FIELDS_EDIT_FORM >) => {
const value = form [ fieldKey ];
if (( fieldValue ?? '' ). trim () === value ?. trim ()) {
goBack ();
return ;
}
if ( isReportFieldTitle ) {
updateReportName ( report . reportID , value , report . reportName ?? '' );
goBack ();
} else {
if ( value !== '' ) {
updateReportField (
{ ... report , reportID: report . reportID },
{ ... reportField , value },
reportField ,
policy as unknown as Policy ,
isASAPSubmitBetaEnabled ,
session ?. accountID ?? CONST . DEFAULT_NUMBER_ID ,
session ?. email ?? '' ,
hasViolations ,
recentlyUsedReportFields ,
hasOtherViolations ,
);
}
goBack ();
}
};
Title Field Handling
The title field receives special handling:
// From src/pages/EditReportFieldPage.tsx
const fieldValue = isReportFieldTitle
? getReportNameFromReportNameUtils ( report , reportAttributesByReportID ) || ( isPolicyFieldListEmpty ( policy ) ? CONST . REPORT . DEFAULT_EXPENSE_REPORT_NAME : '' )
: ( reportField . value ?? reportField . defaultValue );
Deleting Report Fields
Field Deletion
Deletable fields can be removed from reports:
// From src/pages/EditReportFieldPage.tsx
const handleReportFieldDelete = async () => {
const result = await showConfirmModal ({
title: translate ( 'workspace.reportFields.delete' ),
prompt: translate ( 'workspace.reportFields.deleteConfirmation' ),
confirmText: translate ( 'common.delete' ),
cancelText: translate ( 'common.cancel' ),
danger: true ,
shouldEnableNewFocusManagement: true ,
});
if ( result . action !== ModalActions . CONFIRM ) {
return ;
}
Navigation . setNavigationActionToMicrotaskQueue (() => {
goBack ();
setTimeout (() => {
deleteReportField ( report . reportID , reportField );
}, CONST . ANIMATED_TRANSITION );
});
};
const menuItems : PopoverMenuItem [] = [];
const isReportFieldDeletable = reportField . deletable && reportField ?. fieldID !== CONST . REPORT_FIELD_TITLE_FIELD_ID ;
if ( isReportFieldDeletable ) {
menuItems . push ({
icon: icons . Trashcan ,
text: translate ( 'common.delete' ),
onSelected : () => {
handleReportFieldDelete ();
},
shouldCallAfterModalHide: true ,
});
}
Field Deletion Deleting a report field removes it from the report permanently. This action cannot be undone. The title field cannot be deleted.
Field Permissions
Field Disabled States
Fields can be disabled based on user permissions and report state:
// From src/pages/EditReportFieldPage.tsx
const isDisabled = isReportFieldDisabledForUser ( report , reportField , policy ) && reportField ?. type !== CONST . REPORT_FIELD_TYPES . FORMULA ;
if ( ! reportFieldsEnabled || ! reportField || ! policyField || ! report || isDisabled ) {
return (
< ScreenWrapper
includeSafeAreaPaddingBottom = { false }
shouldEnableMaxHeight
testID = "EditReportFieldPage"
>
< FullPageNotFoundView shouldShow />
</ ScreenWrapper >
);
}
Required Fields
Required fields must be filled before report submission:
// From src/pages/EditReportFieldPage.tsx
const hasOtherViolations =
report ?. fieldList && Object . entries ( report . fieldList ). some (([ key , field ]) => key !== fieldKey && field . value === '' && ! isReportFieldDisabled ( report , reportField , policy ));
Best Practices
Give fields clear, descriptive names that indicate what information should be entered (e.g., “Project Code” instead of “Code”).
When possible, provide sensible default values to reduce data entry effort.
Only mark fields as required if the information is absolutely necessary. Too many required fields can slow down the submission process.
Use Dropdowns for Consistency
Use dropdown fields instead of text fields when you need consistent values for reporting or categorization.
For formula fields, document the calculation logic clearly so users understand how values are derived.
Common Issues
Field Not Editable If a field cannot be edited:
Check if the report is in a submitted or closed state
Verify you have permission to edit the report
Ensure the field is not a formula field (which are read-only)
Check if the field is disabled in the policy settings
Recently Used Fields New Expensify tracks recently used field values to provide quick suggestions for commonly entered data.
Field Visibility
Report Field Availability
Report fields are only available when:
// From src/pages/EditReportFieldPage.tsx
const isReportFieldTitle = isReportFieldOfTypeTitle ( reportField );
const reportFieldsEnabled = (( isPaidGroupPolicyExpenseReport ( report ) || isInvoiceReport ( report )) && !! policy ?. areReportFieldsEnabled ) || isReportFieldTitle ;
The workspace has report fields enabled, OR
The report is a paid group policy expense report or invoice report, OR
The field is the title field (always available)
Reports Overview Learn about expense reports
Creating Reports Create and manage reports
Workspace Settings Configure workspace field settings