Table
Tables display structured clinical data with inline sparklines, visual reference range bars, and status-coded values. Wrap in Card for grouped presentation.
Laboratory Results
Columns follow clinical reading order: identify the test, read the value, check if it's in range (via the range bar marker color), then assess the trend. Panel groups (like CBC) are collapsible; standalone results sit alongside them in the same table.
Test | Result | Reference Range | Trend | Date |
|---|---|---|---|---|
| Hemoglobin A1c | 6.8 % | 4–5.6 | ↓ 8% since 08/12/2025 | 01/25/2026 |
Complete Blood Count (CBC)(4 components) | ||||
| White Blood Cells | 7.5 K/uL | 4.5–11 | ↑ 10% since 08/12/2025 | 01/25/2026 |
| Hemoglobin | 15.2 g/dL | 13.5–17.5 | ↑ 3% since 08/12/2025 | 01/25/2026 |
| Platelets | 425 K/uL | 150–400 | ↑ 12% since 08/12/2025 | 01/25/2026 |
| Potassium | 6.2 mEq/L | 3.5–5 | ↑ 48% since 08/12/2025 | 01/25/2026 |
Design Notes
Column Order — Clinical Reading Flow
Columns are ordered to match how clinicians scan lab results: Test → Result → Reference Range → Trend → Date. The eye identifies the test name, reads the numeric value, checks whether it falls within range (via the range bar), assesses the trend direction, then notes recency. This left-to-right flow mirrors the cognitive priority of clinical decision-making.
Range Bar — Interpretation Without Labels
The reference range bar replaces text-based status badges entirely. A horizontal track shows the normal zone as a shaded region, with a colored dot marker indicating where the current value sits. Marker color encodes HL7 interpretation: green for Normal (N), amber for High/Low (H/L), and red for Critically High/Low (HH/LL). This removes the need for separate badge components or a legend — the color is the interpretation, visible at a glance.
Result Value Color
Result numbers use a three-tier color system matching the range bar marker: default text for normal values, amber for abnormal (H/L), and red for critical (HH/LL). This reinforces the range bar without requiring the user to look across to the bar for every row.
Sparkline Trends
Each row includes a 72px inline sparkline showing the last 6 readings. The line color matches the current interpretation tier. A percentage-change annotation (e.g. “↑ 12%”) and “since” date are displayed alongside to give immediate context on trajectory and timeframe. Hovering over the sparkline reveals a tooltip with the exact value and date for each data point, positioned above the chart to avoid obscuring the line.
Panel Groups & Standalone Results
Lab results can appear as collapsible panel groups (e.g. CBC with 4 components) or standalone rows (e.g. HbA1c). Panel headers span the full table width with a chevron toggle on the right edge. Component rows within a panel are slightly indented and use a smaller font size to establish visual hierarchy. Standalone results render at the same level as panel headers. This structure mirrors how lab panels are ordered in clinical systems.
Compact Card Layout
The card uses zero internal padding (py-0 gap-0 overrides) with a slim title bar separated by a border. Column headers use reduced vertical padding. Data rows use py-2.5 for density without sacrificing readability. Critical rows receive a subtle red background tint to draw attention without overwhelming the table.
HL7 FHIR Interpretation Codes
Values follow the HL7 FHIR Observation Interpretation code system: N (Normal), H (High), L (Low), HH (Critically High), LL (Critically Low). Note that Synthea fixture data does not include interpretation or referenceRange fields on Observations — interpretation must be derived at display time using LOINC-based reference ranges.
Medications
Data mirrors FHIR MedicationRequest structure. The medication column contains the full RxNorm display string (drug + dose + form) from medicationCodeableConcept.text. Frequency is derived from dosageInstruction timing data. Reason comes from reasonReference.display. Separate dosage and route columns are unnecessary — both are embedded in the medication name.
Medication | Frequency | Reason | Status | Prescribed | Requester |
|---|---|---|---|---|---|
| Lisinopril 10 MG Oral Tablet | 1x daily | Hypertension | Active | 01/15/2025 | Dr. Terri Gutmann |
| Metformin hydrochloride 500 MG Oral Tablet | 2x daily | Diabetes mellitus type 2 | Active | 03/20/2025 | Dr. Terri Gutmann |
| Atorvastatin 20 MG Oral Tablet | 1x daily | Hyperlipidemia | Active | 06/10/2024 | Dr. Maia Williams |
| Ibuprofen 200 MG Oral Tablet | As needed | Osteoarthritis of knee | Active | 09/14/2025 | Dr. Maia Williams |
| Completed | |||||
| Warfarin Sodium 5 MG Oral Tablet | 1x daily | Atrial fibrillation | Completed | 12/01/2024 | Dr. Terri Gutmann |
Design Notes
Column Order — Clinical Reading Flow
Columns follow clinical scanning priority: Medication → Frequency → Reason → Status → Prescribed → Requester. The clinician identifies the drug and dose, checks the schedule, understands why it was prescribed, confirms whether it's still active, then notes when it started and who ordered it. This mirrors the natural question flow when reviewing a medication list.
FHIR Data Mapping
All columns map directly to FHIR MedicationRequest fields. The medication name uses the full RxNorm display string from medicationCodeableConcept.text which includes drug name, dose, and form (e.g. “Lisinopril 10 MG Oral Tablet”). This eliminates the need for separate dosage and route columns — both are embedded in the medication name. Frequency is derived from dosageInstruction[].timing.repeat or falls back to dosageInstruction[].text. About 20% of MedicationRequests in Synthea fixtures lack dosageInstruction entirely.
Reason for Prescribing
The reason column surfaces clinical intent from reasonReference[].display or reasonCode[].text. This connects the medication to the underlying condition (e.g. Lisinopril → Hypertension), giving context that a drug name alone cannot. In real workflows, this helps catch inappropriate prescriptions and supports medication reconciliation.
Status Values
FHIR MedicationRequest uses active and completed — not “discontinued” as commonly seen in EHR interfaces. The positive badge variant (green) marks active medications, and neutral (gray) marks completed ones. Status is placed mid-table as a key scanning signal — the clinician needs to quickly distinguish current from historical medications.
Dropped Columns
Dosage and Route are intentionally omitted. Synthea's RxNorm display strings embed both (e.g. “500 MG Oral Tablet”), making separate columns redundant. Route in particular has extremely low information density — nearly all outpatient medications are oral. Removing these columns reduces visual noise and lets the table focus on clinically actionable fields.
Requester vs Prescriber
The column is labeled “Requester” to match the FHIR field name (requester.display). In FHIR, the requester is the practitioner who authored the medication order, sourced via NPI reference. This is placed last as the least-scanned column — clinicians prioritize what the drug is and whether it's active over who prescribed it.
Immunizations
Data mirrors FHIR Immunization resources. The vaccine column uses the CVX display string from vaccineCode.text. All Synthea immunizations have status “completed” — there are no pending or refused records in the fixtures.
Vaccine | Date | Location |
|---|---|---|
| Influenza, seasonal, injectable, preservative free | 10/15/2025 | River's Edge Primary Care LLC |
| Influenza, seasonal, injectable, preservative free | 10/22/2024 | River's Edge Primary Care LLC |
| COVID-19, mRNA, LNP-S, PF, 100 mcg/0.5mL dose | 06/02/2024 | University of MA Med Ctr |
| COVID-19, mRNA, LNP-S, PF, 30 mcg/0.3 mL dose | 01/15/2024 | University of MA Med Ctr |
| Td (adult), 5 Lf tetanus toxoid, preservative free, adsorbed | 08/09/2023 | River's Edge Primary Care LLC |
| Zoster vaccine, live | 03/14/2023 | River's Edge Primary Care LLC |
| Hep B, adult | 11/20/2022 | University of MA Med Ctr |
Design Notes
Column Order
Vaccine → Date → Location. The clinician identifies which vaccine was given, checks when it was administered, and notes where. Status is omitted as a column because all Synthea immunizations are “completed” — in a production system with pending/refused states, a status column would be added.
FHIR Data Mapping
The vaccine name comes from vaccineCode.text, which contains the CVX display string (e.g. “Influenza, seasonal, injectable, preservative free”). Date maps to occurrenceDateTime and location to location.display. The CVX code (vaccineCode.coding[0].code) is available in the FHIR data but omitted from display — the full vaccine name provides sufficient identification for clinical review.
Fixture Characteristics
Synthea generates 73 immunization records across 5 patient bundles with 7 distinct vaccine types. Influenza dominates (50 of 73), followed by COVID-19 variants (10), tetanus (5), zoster (4), hepatitis B (3), and meningococcal (1). All records include primarySource: true and a location reference. No optional FHIR fields (site, route, doseQuantity, performer) are present in the Synthea data.
Omitted Fields
Several FHIR Immunization fields are absent from Synthea fixtures and therefore not displayed: site (injection site), route (administration route), doseQuantity, performer (administering practitioner), and note. A production implementation would add columns for these if populated.
Basic Table
Simple key-value or props reference table using the shared compact card wrapper and consistent column header styling.
Name | Type | Default |
|---|---|---|
| variant | string | "default" |
| size | string | "md" |
Shared Table Styling
Card Wrapper
All tables use Card with py-0 gap-0 overrides to eliminate the default vertical padding and gap. A slim title bar sits at the top, separated from the table by a border. This keeps the card chrome minimal so the data is the focus.
Column Headers
All column headers share the same class: uppercase, text-xs, muted foreground color, with px-4 py-2 padding and a bg-muted/30 background. This creates a consistent, unobtrusive header row across all table variants.
Data Rows
Data cells use px-4 py-2 to py-2.5 padding depending on content density, with text-sm font sizing. Rows are separated by divide-y borders. The first column is typically font-medium to anchor the eye, while secondary columns like dates use text-muted-foreground.
Status Badges
Status indicators use the Badge component at sm size. The positive variant (green) is used for active states, and neutral (gray) for inactive or discontinued states. Badges are placed in the final column as a scannable status indicator.