OCR Records UI
Full-featured data grid, inline editing, export/import sync, and roster matching for extracted student records.
The @nexa-ed/react package ships two ways to embed the records UI: a fully self-contained drop-in (StudentRecordsTable) and a lower-level composable grid (RecordDataGrid) for custom data layers. Both live under the react section of this SDK.
StudentRecordsTable
The highest-level component. Pass only a fileId — everything else is handled internally: paginated fetching, four filter toggles, inline cell editing, column sort, drag-and-drop column reorder, multi-row selection, bulk operations, XLSX/CSV/JSON export, import sync with diff preview, and a full roster matching column.
Built-in features
| Feature | Details |
|---|---|
| Filters | Students only · Partial matches · Hide fully missing · Warnings only |
| Inline editing | Double-click or Enter to open a cell; auto-saves on blur / Tab / Enter / arrow keys |
| Column sort | Click header → asc → desc → off. Numeric columns compared as numbers |
| Column reorder | Drag headers; Reset columns restores server order |
| Row selection | Checkbox, Shift+click range, Ctrl+click anchor range |
| Bulk operations | Mass-update a column across selected rows; delete selected rows |
| Add rows | Inline form per page; rows appended after the last existing record |
| Renumber | Re-sequences a numeric column from a chosen start number |
| Export | XLSX (hidden __record_id), CSV, JSON — respects active filters and column order |
| Sync from file | Upload → diff preview (new / updated / unchanged / skipped) → apply |
| NEW badge | Rows created via sync show a green NEW pill in the # column |
| Roster column | RosterCell per row; manual reassignment popover; Re-run matching button |
RecordDataGrid
Lower-level grid. All features are opt-in via props — omit a prop group to disable it entirely. Use this when you control your own data-fetching layer.
Props reference
| Prop | Type | Description |
|---|---|---|
records | RecordRow[] | Required. Rows to display. |
onSave | (id, data) => Promise<void> | Enables inline editing. Called on cell commit. |
saving | string | null | ID of the row currently saving — dims that row. |
diffBase | Record<id, recordData> | Pre-edit snapshot. Changed cells render with a blue tint. |
label | string | Optional heading above the grid. |
columnOrder | string[] | Controls the display order of data columns. |
onAddRows | (pageNumber, rows) => Promise<void> | Enables the + Add rows button in the footer. |
onMassUpdate | (col, value) => Promise<void> | Enables the column-level mass-update action bar. |
onDeleteRow | (id) => Promise<void> | Enables the per-row delete icon. |
onDeleteRows | (ids[]) => Promise<void> | Enables Delete selected in the row action bar. |
onMassUpdateRows | (ids[], col, value) => Promise<void> | Enables Set value in column in the row action bar. |
sortCol | string | null | Currently sorted column. |
sortDir | "asc" | "desc" | null | Sort direction. |
onToggleSort | (col) => void | Called when a column header is clicked. |
onRenumber | (records, col, start) => Promise<void> | Enables the Renumber action bar. |
lastSerialNumber | number | null | Last serial from the previous page — continue a multi-page sequence. |
onRenumberComplete | (lastSerial) => void | Called with the last serial after renumber finishes. |
rosterEntries | Map<string, RosterEntry> | Enables the Roster column. |
onAssignRoster | (recordId, rosterId | null) => void | Called when a manual assignment is made or cleared. |
onRerunMatching | () => void | Shows the Re-run matching button in the footer. |
onColumnReorder | (newOrder: string[]) => void | Enables column drag-and-drop. |
onResetColumnOrder | () => void | Called when Reset columns is clicked. |
newRecordIds | Set<string> | IDs of rows just created via import sync — shown with a green NEW badge. |
Highlighting changed cells with diffBase
Capture a snapshot of recordData before a bulk operation and pass it as diffBase. Any cell that now differs from the snapshot renders with a blue tint — useful for post-import review.
Building the rosterEntries map
Screenshot
diffBase in action — blue-tinted cells show values changed since the snapshot was taken
RosterCell
Badge + search popover for linking a single record row to a roster entry. Used inside RecordDataGrid but composable anywhere.
Badge colours
| Colour | rosterMatchStatus | Meaning |
|---|---|---|
| Green | "auto" | Linked by the trigram name-similarity algorithm |
| Amber | "manual" | Manually assigned via the popover |
| None | null / "unmatched" | Not linked |
The popover search filters across name, externalId, classGroup, and all metadata values. Metadata key/value pairs render as small gray tag pills below each result.
Custom records page
If StudentRecordsTable is too opinionated and you need full control over data fetching:
Types
Info
For a visual walkthrough of every feature with screenshot slots, see the Records Guide page
in your Nexa Ed dashboard at /dashboard/records-guide.