A practical guide to React Native document comparison, covering financial data modeling, source highlighting, mobile layouts, and lessons from five engineering companies.
Comparing financial documents involves more than highlighting changed text. A reviewer may need to establish whether two statements cover the same period, whether an amount uses different units, or whether a missing value reflects an extraction failure.
A useful interface makes those distinctions visible. It connects each detected difference to its source and lets reviewers record a decision without losing context.
This guide focuses on React Native for iOS and Android, while keeping the comparison model reusable in a React web application. The architecture and implementation examples below are recommendations, rather than a reproduction of any company’s internal system.
What Should a Financial Document Comparison Interface Compare?
The first design decision concerns the meaning of “comparison.”
Different workflows require different rules:
| Workflow | Main comparison question | Important context |
|---|---|---|
| Statement revision review | What changed between document versions? | Document identity and revision |
| Period comparison | How did reported figures change? | Period, currency, and units |
| Invoice reconciliation | Do corresponding records agree? | Invoice ID, tax, and line items |
| Loan document review | Which terms differ? | Definitions, dates, and clauses |
A textual difference does not necessarily represent a financial discrepancy. “1.2 million” and “1,200,000” may describe the same amount. Conversely, identical numbers can mean different things if one document reports dollars and another reports thousands of dollars.
The interface should explain what comparison was performed before presenting its conclusions.
Separate Extraction, Matching, and Presentation
A maintainable architecture gives each stage a clear responsibility:
- A backend receives and processes the documents.
- An extraction service identifies text, tables, and source locations.
- A normalization layer interprets currencies, periods, and units.
- A comparison service matches corresponding fields or records.
- The React Native application presents results and captures review decisions.
For example, Amazon Textract documents support for extracting table cells, merged cells, headers, and other table relationships. Extraction supplies structure; application-specific logic must still decide which values belong together.
For large or scanned files, an asynchronous backend job is a sensible starting point. The mobile application can display processing status and retrieve results when available, rather than performing heavy document analysis during rendering.
Model Evidence Alongside Every Value
A comparison result should contain more than an old value and a new value.
Each value needs enough context to answer: where did this come from, and how was it interpreted?
A simplified TypeScript model might look like this:
type Evidence = {
documentVersionId: string;
page: number;
box: {
left: number;
top: number;
width: number;
height: number;
};
};
type MoneyField = {
rawText: string;
amount: string | null;
currency: string | null;
period: string | null;
evidence: Evidence;
};
type ComparisonRow = {
id: string;
label: string;
before: MoneyField | null;
after: MoneyField | null;
result:
| "unchanged"
| "changed"
| "missing"
| "not-comparable"
| "needs-review";
};Here, amount represents a validated decimal string normalized to base currency units. The original text remains available for inspection.
Keeping not-comparable separate from changed prevents a currency mismatch or uncertain period match from appearing as a confirmed financial difference.
Normalize Monetary Values Before Calculating Differences
Avoid treating formatted document strings as numbers directly.
Removing punctuation from 1.234,56, for example, can produce the wrong value if the parser assumes a different locale. Parentheses, currency symbols, and document-level unit declarations also need explicit interpretation.
A practical normalization process should:
- Identify the number format from document context.
- Resolve currency and reporting units.
- Preserve missing and uncertain values.
- Apply documented rounding rules.
For calculations that require decimal arithmetic, decimal.js provides an arbitrary-precision decimal type. Its precision is configurable, so the application still needs suitable precision and rounding settings for its domain.
The following helper illustrates a limited comparison rule. Its inputs must already be validated finite decimal strings, normalized to the same units and associated with compatible periods.
import Decimal from "decimal.js";
type Money = {
amount: string;
currency: string;
};
function calculateDelta(
before: Money | null,
after: Money | null
): string | null {
if (!before || !after) return null;
if (before.currency !== after.currency) return null;
return new Decimal(after.amount)
.minus(before.amount)
.toString();
}A null result should lead to an explanatory state in the interface. It should never silently become zero.
Match Financial Records Before Highlighting Changes
Comparing tables by row position is fragile. A newly inserted line item can shift every subsequent row and create misleading differences.
Prefer stable identifiers when available: transaction IDs, invoice references, account codes, or contractual section identifiers.
When identifiers are unavailable, matching may require a combination of fields such as date, description, amount, and document section. Ambiguous matches should remain reviewable.
The interface should distinguish:
- A changed value in a matched record.
- A newly added record.
- A removed record.
- A record whose match remains uncertain.
This gives reviewers a clearer explanation than a single generic “difference” label.
Build the Mobile Interface Around Review Tasks
Two full document pages displayed side by side can become difficult to read on a phone.
A more usable default is a difference list. Each row shows the field name, previous value, current value, result label, and an action to inspect the source.
On wider screens, the same data can support paired columns or a document-and-details layout.
A minimal React Native rendering example could be:
import { FlatList, Pressable, Text } from "react-native";
type ReviewListProps = {
rows: ComparisonRow[];
onInspect: (row: ComparisonRow) => void;
};
export function ReviewList({
rows,
onInspect,
}: ReviewListProps) {
return (
<FlatList
data={rows}
keyExtractor={(row) => row.id}
renderItem={({ item }) => (
<Pressable
accessibilityRole="button"
accessibilityLabel={[
item.label,
`Previous: ${item.before?.rawText ?? "Not available"}`,
`Current: ${item.after?.rawText ?? "Not available"}`,
`Result: ${item.result}`,
].join(". ")}
accessibilityHint="Opens the supporting document evidence"
onPress={() => onInspect(item)}
>
<Text>{item.label}</Text>
<Text>
Previous: {item.before?.rawText ?? "Not available"}
</Text>
<Text>
Current: {item.after?.rawText ?? "Not available"}
</Text>
<Text>{item.result}</Text>
</Pressable>
)}
/>
);
}This example assumes the types from the earlier model. It demonstrates presentation, rather than a complete document viewer.
React Native’s FlatList documentation notes that offscreen item state is not preserved. Reviewer decisions therefore belong in external state or persisted records, rather than exclusively inside individual rows.
Connect Every Difference to the Original Page
Selecting “Inspect source” should open the correct document version and page, then highlight the supporting region.
Textract’s bounding-box coordinates use ratios of page width and height. This allows a viewer to translate the coordinates into its rendered page dimensions.
For an unrotated page:
const highlight = {
left: pageOffsetX + box.left * renderedPageWidth,
top: pageOffsetY + box.top * renderedPageHeight,
width: box.width * renderedPageWidth,
height: box.height * renderedPageHeight,
};The viewer must also account for zoom, rotation, cropping, and page offsets. Those transformations should apply consistently to both the page and its overlay.
Avoid synchronizing documents solely by scroll percentage. Corresponding evidence may appear on different pages after layout changes.
Make Accessibility and Performance Part of the Design
Differences need text labels as well as color. A reviewer should be able to distinguish “Changed,” “Missing,” and “Needs review” without relying on red and green highlights.
React Native provides accessibility properties for labels and integration with VoiceOver and TalkBack, with platform-specific behavior that requires testing on both operating systems.
For performance, load document previews on demand, paginate large result sets, and avoid recomputing comparisons during every render.
Profile release builds on representative devices. React Native’s performance guidance specifically recommends release-build testing because development mode affects JavaScript performance.
What Do Leading React Native Companies Demonstrate?
Public sources establish related engineering practices at the following five companies. They do not establish that every company has built the exact financial document comparison workflow described here.
| Company | Documented practice | Relevance to financial document comparison interfaces |
|---|---|---|
| GeekyAnts | Its banking case study describes using XState, SWR, Reanimated, and Restyle. | Relevant approaches for managing review states, fetching comparison results, implementing interactions, and maintaining consistent styling. |
| Microsoft | Uses React Native for selected experiences in Word, Excel, and PowerPoint, including commenting and shared canvas experiences. | Demonstrates React Native integration within document-centric applications across platforms. |
| Expensify | Maintains a public React Native application for financial collaboration and expense management. | Offers inspectable examples relevant to financial workflows and cross-platform interfaces. |
| Software Mansion | Develops Reanimated, which supports UI-thread animations and interactions. | Provides tooling for document gestures, transitions, and animated source highlights. |
| Shopify | Develops FlashList, which recycles components for React Native lists. | Provides an option to evaluate for large lists of comparison results and financial records. |
The company examples are supported by their published case studies, service descriptions, and library documentation. Their relevance is architectural; it is not evidence that they use the sample implementation above.
Protect Documents and Preserve Review Decisions
React Native’s security guidance identifies AsyncStorage as unencrypted storage and warns against placing secrets in the application bundle. Sensitive documents and credentials require an explicit storage and access design.
A recommended backend design should authorize access to both documents and their comparison results. Review submissions should reference immutable document versions and a comparison revision, allowing the server to detect stale decisions.
Testing should include reordered rows, duplicate records, mixed currencies, changed units, rotated scans, uncertain extraction, and interrupted submissions.
The most useful financial document comparison interface makes its reasoning inspectable. Reviewers should understand what changed, see the evidence, and recognize where the system still needs a human decision.





















Add Comment