Philosophy
New Expensify is designed to work perfectly offline. Users can perform almost any action without an internet connection, and those actions are automatically synchronized when connectivity is restored.Core Principle: Allow users to do as much as possible when offline. Assume most requests will succeed and proceed optimistically.
Offline UX Patterns
Every feature in New Expensify follows one of these offline patterns:Pattern A: Optimistic Without Feedback
When to use: The user needs instant feedback but doesn’t need to know when the server confirms the change. Example: Pinning a chat- Use
API.write() - Only provide
optimisticData - UI updates immediately
- No loading indicators needed
Pattern B: Optimistic WITH Feedback
When to use: The user needs to know that data is pending server confirmation. Example: Sending a chat message- Use
API.write() - Include
optimisticData,successData, andfailureData - Add
pendingActionto show pending state - Wrap UI in
OfflineWithFeedbackcomponent
- Adding: Item shown at 50% opacity when offline
- Updating: Item shown at 50% opacity when offline
- Deleting: Item shown with strikethrough when offline
- Error: Item shown with red error message and dismiss button
Pattern C: Blocking Form
When to use:- Form requires server validation
- Server response is unpredictable
- Moving money or other critical operations
- Use
FormAlertWithSubmitButton - Set
enabledWhenOffline={false} - Users can fill out form offline, but can’t submit
- Data is saved locally via form draft
Pattern D: Full Page Blocking
When to use:- READ request where stale data is unacceptable
- Data must be fetched from server before display
- Only use as last resort
- Wrap component in
FullPageOfflineBlockingView - Only show when offline AND data is not available
- Provide clear instructions to user
Pattern None: No Offline Behavior
When to use:- No server interaction
- OR data is READ and stale data is acceptable
- Use
API.read()for server data - No special offline handling
- Shows stale data until fresh data loads
Choosing the Right Pattern
Request Queue
How It Works
WRITE requests are queued and replayed when online:- User performs action while offline
API.write()creates request with optimistic data- Request is persisted to disk (via Onyx)
- Optimistic data is applied immediately
- Request waits in queue
- When online, queue processes requests in order
- Success/failure data is applied based on response
Sequential Queue
Requests are processed sequentially to maintain order:Viewing the Queue
During development:Conflict Resolution
What Are Conflicts?
Conflicts occur when:- User makes changes offline on Device A
- User makes different changes online on Device B
- Device A comes online and tries to sync
Built-In Strategies
1. Last Write Wins
Default behavior - the most recent change is kept:2. Duplicate Detection
Prevents duplicate requests:3. Custom Conflict Resolution
Network Detection
Using Network State
Subscribing to Network Changes
Error Handling
Displaying Errors
Use the Red Brick Road (RBR) pattern to guide users to errors:Clearing Errors
Retry Logic
Failed requests are automatically retried:Pending States
Pending Actions
Field-Level Pending States
For partial updates:Testing Offline Behavior
Simulating Offline Mode
Testing Optimistic Updates
Best Practices
1. Always Provide Optimistic Data
2. Handle Failures Gracefully
3. Use Appropriate Patterns
Choose the right offline pattern for your use case (see flowchart above).4. Test Offline Scenarios
Always test:- Action performed offline
- Action performed online
- Error scenarios
- Network changes during action
5. Provide Clear Feedback
UseOfflineWithFeedback to show pending states visually.
Common Pitfalls
1. Not Providing Failure Data
2. Blocking When Not Necessary
3. Not Handling Errors
Performance Considerations
Batch API Calls
Group related updates:Optimize Onyx Updates
Next Steps
State Management
Learn more about Onyx
API Reference
Understand API patterns
Testing
Test offline behavior
Best Practices
Follow offline-first best practices
