Components / Clinical
Lab results table
Lab values flagged against the reference ranges you pass, with a sparkline of earlier results. Flags read as text and an icon, so they never depend on color alone.
| Test | Result | Trend |
|---|---|---|
| Glucose, fastingOct 1, 2026Range: 70–99 mg/dL | 118 mg/dLHigh | |
| Hemoglobin A1cOct 1, 2026Range: 4.0–5.6 % | 6.1 %High | |
| SodiumOct 1, 2026Range: 135–145 mmol/L | 133 mmol/LLow | |
| PotassiumOct 1, 2026Range: 3.5–5.1 mmol/L | 6.4 mmol/LCritical high | |
| CreatinineOct 1, 2026Range: 0.60–1.20 mg/dL | 0.90 mg/dLNormal | |
| HDL cholesterolOct 1, 2026Range: ≥ 40 mg/dL | 52 mg/dLNormal | No earlier results |
| Urine proteinOct 1, 2026Range: Negative | NegativeNormal | No earlier results |
Installation
In a project set up as in Installation, run:
bunx shadcn@4.22.1 add https://organui.com/r/lab-results.json
Or by name: bunx shadcn@4.22.1 add @organui/lab-results.
The source installs into your UI components directory, along with shadcn's table if you do not have it yet. It holds no state and uses no hooks, so it renders in server and client components alike.
Usage
import { LabResultsTable, type LabResult } from "@/components/ui/lab-results"
const results: LabResult[] = [
{
id: "glucose",
name: "Glucose, fasting",
value: 118,
unit: "mg/dL",
date: "2026-10-01",
referenceRange: { low: 70, high: 99, criticalLow: 40, criticalHigh: 400 },
history: [
{ value: 92, date: "2025-10-06" },
{ value: 104, date: "2026-05-18" },
{ value: 118, date: "2026-10-01" },
],
},
{
id: "urine-protein",
name: "Urine protein",
value: "Negative",
flag: "normal",
referenceRange: { text: "Negative" },
},
]
export function Results() {
return <LabResultsTable results={results} caption="Basic metabolic panel" />
}Reference ranges and flags
Ranges are data, not built in, because they vary by laboratory, age, sex and method. Pass low and high as the inclusive limits of normal, either one alone for a one-sided range, and criticalLow or criticalHigh for values outside which a result is critical. Critical limits are checked first. A numeric value with no limits is shown as not flagged.
Text results, such as "Negative", are never compared with a range. Set referenceRange.text to print the expected result, and flag to show the flag the laboratory reported. A flag you pass always wins over the computed one. The labFlag and formatReferenceRange helpers are exported for use elsewhere, such as a summary of abnormal results.
Every flag is a word and an icon: an up or down arrow for high or low, a warning triangle for critical or abnormal, and a check for normal. Critical flags also use your destructive color and abnormal values are bold. Rows carry a data-flag attribute for your own styling.
Trend
Pass history, including the current result, to draw a sparkline. Points are sorted by date. The shaded band is the reference range, and points outside it are drawn as rings. The sparkline's accessible name describes the trend in words, such as "Glucose, fasting trend, 4 results from Oct 6, 2025 to Oct 1, 2026: 92 to 118 mg/dL, rising". Set showTrend={false} to drop the column.
Dates are ISO 8601 strings and show as UTC dates in US English, so the server and client render the same text. Pass formatDate to use your own locale or time zone. Set decimals on a result to fix its decimal places across the value, range and trend.
Layout
The table sizes to its container rather than the viewport. Below 32rem wide, the reference range moves under the test name so the table fits a phone without scrolling sideways.
A display component, not clinical decision support. It does not convert units, interpret results or choose reference ranges, and the example values are illustrative.