Create a table with pagination
Key concepts
useFhirSearch()will return a query that fetches data for a type of FHIR resource. It also accepts search parameters that can either be a function or a search parameters string.<FhirTable />a BonFHIR component that displays FHIR data in a table. Each column can be customized with built-in support for sorting and pagination.useFhirSearchController(): setup and manage FHIR search functionality through a simple interface<FhirPagination />: a BonFHIR component that controls FhirTable pagination via the search controller
Step by step
This guide builds off of the previous guide: Display FHIR data.
-
Create a new React component called
PatientReportsTablethat receives a patient ID as a prop. Import this component inpages/Home.tsxand add the table component inside the page, passing inpatient.id.src/components/PatientReportsTable.tsximport { FC, ReactElement } from "react";
type PatientReportsTableProps = {
patientId: string;
};
const PatientReportsTable: FC<PatientReportsTableProps> = ({
patientId,
}): ReactElement => {
return (
<div>
<p>{patientId}</p>
</div>
);
};
export default PatientReportsTable;src/pages/Home.tsx<PatientReportsTable patientId={patient.id} /> -
Create the search query with
useFhirSearchfor the"DiagnosticReport"resource type. BonFHIR has built-in type support for FHIR resource content, so the official HL7 FHIR documentation can be used to understand what search parameters are available.For this example, the search function will search for resources where the subject is a patient with the value of the patientId prop. The search function also indicates that the data should be sorted by property
issuedwith-prefix to sort in reverse.const diagnosticReportsQuery = useFhirSearch("DiagnosticReport", (search) =>
search.patient(patientId)._sort("-issued"),
); -
Inside a FhirQueryLoader, setup the FhirTable. The first parameter will be the expanded query. Each column of the table should be configured with:
key: the name of the resource propertytitle: the column headerrender: a function that receives the individual resource and prepares the value. TheFhirValuecomponent can be used here to simplify formatting.
In this example, we will display the Diagnostic Report code, date issued and status.
<FhirQueryLoader query={diagnosticReportsQuery}>
<FhirTable
{...diagnosticReportsQuery}
columns={[
{
key: "code",
title: "Test",
render: (diagnosticReport) => (
<FhirValue type="CodeableConcept" value={diagnosticReport.code} />
),
},
{
key: "issued",
title: "Date Issued",
render: (diagnosticReport) => (
<FhirValue type="date" value={diagnosticReport.issued} />
),
},
{
key: "status",
title: "Status",
render: (diagnosticReport) => (
<FhirValue type="string" value={diagnosticReport.status} />
),
},
]}
/>
</FhirQueryLoader> -
To add pagination, define a search controller with
useFhirSearchControllerabove the query. The search controller manages sorting and paginating FHIR resources. Initialize the search controller with the sort order for the corresponding resource type, as well as a page size.const searchController = useFhirSearchController<DiagnosticReportSortOrder>({
pageSize: 5,
});Update the query
searchfunction with_count(searchController.pageSize)and_total("accurate")to indicate how many resources to retrieve and the total number of resources that are available. Finally, include a third argument thesearchController.pageUrl, which is how the query knows which page of resources to fetch.const diagnosticReportsQuery = useFhirSearch(
"DiagnosticReport",
(search) =>
search
.patient(patientId)
._sort("issued")
._count(searchController.pageSize)
._total("accurate"),
searchController.pageUrl,
); -
Connect the search controller to the
FhirTableby including it as a prop.<FhirTable
{...diagnosticReportsQuery}
{...searchController}Insert the
FhirPaginationcomponent below the table.<FhirPagination {...diagnosticReportsQuery} {...searchController} />
Final result
Here is the output of this example with a paginated table of Diagnostic Reports for the patient!

import { DiagnosticReportSortOrder } from "@bonfhir/core/r4b";
import { useFhirSearch } from "@bonfhir/query/r4b";
import {
FhirPagination,
FhirQueryLoader,
FhirTable,
FhirValue,
useFhirSearchController,
} from "@bonfhir/react/r4b";
import { FC, ReactElement } from "react";
type PatientReportsTableProps = {
patientId: string;
};
const PatientReportsTable: FC<PatientReportsTableProps> = ({
patientId,
}): ReactElement => {
const searchController = useFhirSearchController<DiagnosticReportSortOrder>({
pageSize: 5,
});
const diagnosticReportsQuery = useFhirSearch(
"DiagnosticReport",
(search) =>
search
.patient(patientId)
._sort("issued")
._count(searchController.pageSize)
._total("accurate"),
searchController.pageUrl,
);
return (
<FhirQueryLoader query={diagnosticReportsQuery}>
<FhirTable
{...diagnosticReportsQuery}
{...searchController}
columns={[
{
key: "code",
title: "Test",
render: (diagnosticReport) => (
<FhirValue type="CodeableConcept" value={diagnosticReport.code} />
),
},
{
key: "issued",
title: "Date Issued",
render: (diagnosticReport) => (
<FhirValue type="date" value={diagnosticReport.issued} />
),
},
{
key: "status",
title: "Status",
render: (diagnosticReport) => (
<FhirValue type="string" value={diagnosticReport.status} />
),
},
]}
/>
<FhirPagination {...diagnosticReportsQuery} {...searchController} />
</FhirQueryLoader>
);
};
export default PatientReportsTable;
import { useFhirRead } from "@bonfhir/query/r4b";
import { FhirQueryLoader, FhirValue } from "@bonfhir/react/r4b";
import { Group, Paper, Stack, Text } from "@mantine/core";
import PatientReportsTable from "../components/PatientReportsTable";
export default function Home() {
const patientQuery = useFhirRead(
"Patient",
"afb2bbf9-872c-47a9-9b31-2a737ed65f0b",
);
return (
<FhirQueryLoader query={patientQuery}>
{(patient) => (
<Paper p="xl">
<Paper shadow="xs" p="xl">
<Stack gap="sm">
<Text size="xl">
<FhirValue type="HumanName" value={patient.name} />
</Text>
<Group>
<Text fw={600}>Birthday: </Text>
<FhirValue type="date" value={patient.birthDate} />
</Group>
<Group>
<Text fw={600}>Address: </Text>
<FhirValue type="Address" value={patient.address} />
</Group>
<Group>
<Text fw={600}>Contact: </Text>
<FhirValue type="ContactPoint" value={patient.telecom} />
</Group>
</Stack>
</Paper>
<br />
<PatientReportsTable patientId={patient.id} />
</Paper>
)}
</FhirQueryLoader>
);
}