React Adapter
Memoized analytics hooks and SVG components from @glucoseiq/react.
@glucoseiq/react wraps the core analytics and SVG renderers. Use hooks for
typed data or components for a rendered SVG.
npm install @glucoseiq/react @glucoseiq/coreReact 18 or newer is the only peer dependency. The root is a Client Component
package; use @glucoseiq/core directly for server-only work.
Choose the smallest API that fits
| API | Returns | Best for |
|---|---|---|
useGlucoseAnalysis | AnalyzeGlucoseResult | Dashboard summaries and retrospective reports |
useAGPProfile | Percentile bins across a 24-hour clock | Custom AGP charts in D3, Visx, Canvas, or another renderer |
useGlucoseIQScore | Score, rating, and zone | A compact wellness summary |
useMealResponse | Baseline, peak, delta, timing, and iAUC | Post-meal detail views |
useGlucoseLive | Latest reading, derived trend, and staleness | Current glucose views |
AgpChart, TirBar, TrendTile | Inline SVG inside a wrapper element | Chart-library-free SVG visuals |
All hooks accept the same GlucoseReading[] contract as @glucoseiq/core.
Build a report-driven component
'use client'
import type { AnalyzeGlucoseOptions, GlucoseReading } from '@glucoseiq/core'
import { useGlucoseAnalysis } from '@glucoseiq/react'
const options: AnalyzeGlucoseOptions = {
timeZone: 'America/Detroit',
}
export function Summary({ readings }: { readings: GlucoseReading[] }) {
const report = useGlucoseAnalysis(readings, options)
if (!report.valid || !report.timeInRange) {
return <p>No valid glucose readings are available.</p>
}
return (
<dl>
<div>
<dt>Time in range</dt>
<dd>{report.timeInRange.inRange.percentage.toFixed(1)}%</dd>
</div>
<div>
<dt>GMI</dt>
<dd>{report.gmi.toFixed(1)}%</dd>
</div>
<div>
<dt>Variability</dt>
<dd>{report.cv.toFixed(1)}%</dd>
</div>
</dl>
)
}The hooks memoize their corresponding core computation. Keep the readings
array and options object stable when their contents have not changed; recreating
either reference on every render causes the analysis to run again.
Add a live view model
useGlucoseLive combines latestReading, computeGlucoseTrend, and
minutesSinceLastReading:
import type { GlucoseReading } from '@glucoseiq/core'
import { useGlucoseLive } from '@glucoseiq/react'
const liveOptions = {
windowMin: 15,
refreshMs: 30_000,
} as const
function CurrentGlucose({ readings }: { readings: GlucoseReading[] }) {
const live = useGlucoseLive(readings, liveOptions)
if (!live.latest || live.minutesSince === null) {
return <p>No current reading.</p>
}
if (live.minutesSince < 0) {
return (
<p role="status">
The latest reading time is ahead of the current clock.
</p>
)
}
return (
<section aria-live="polite">
<strong>{live.latest.value} {live.latest.unit}</strong>
<span>{live.trend.trend}</span>
<time dateTime={live.latest.timestamp}>
{Math.round(live.minutesSince)} min ago
</time>
</section>
)
}Omit refreshMs to disable interval refresh. When provided, it must be a whole
number of milliseconds from 1 through 2_147_483_647; invalid values throw
DomainError with code INVALID_OPTION before a timer is scheduled. A valid
value only advances the staleness clock. It does not poll a CGM source or add
readings. Your application remains responsible for transport and for updating
the array when data arrives.
See Build a Live Glucose View for a polling example and failure states.
Use the SVG components
Each SVG includes a concise image label. Pair it with an adjacent text summary
that states the values and trend a reader needs to understand. A visible
figcaption also serves people who cannot distinguish a chart's colors or
shapes.
import type { GlucoseReading, TIRBarOptions } from '@glucoseiq/core'
import { AgpChart, TirBar, TrendTile } from '@glucoseiq/react'
const tirOptions: TIRBarOptions = { theme: 'dark' }
const agpOptions = {
theme: 'dark',
timeZone: 'America/Detroit',
title: 'Last 14 days',
} as const
interface ChartSummaries {
current: string
timeInRange: string
agp: string
}
interface ChartsProps {
readings: GlucoseReading[]
summaries: ChartSummaries
}
export function Charts({ readings, summaries }: ChartsProps) {
return (
<>
<figure>
<TrendTile readings={readings} />
<figcaption>{summaries.current}</figcaption>
</figure>
<figure>
<TirBar readings={readings} options={tirOptions} />
<figcaption>{summaries.timeInRange}</figcaption>
</figure>
<figure>
<AgpChart
readings={readings}
options={agpOptions}
className="dashboard-chart"
/>
<figcaption>{summaries.agp}</figcaption>
</figure>
</>
)
}Build the summary strings from the same report or live model as the SVG. Include the numeric values and labels that color, position, or a trend glyph would otherwise carry alone.
Each component memoizes a zero-dependency renderer from @glucoseiq/core and
inlines the returned SVG inside a div. className and style apply to that
wrapper. Dimensions, theme, time zone, and titles belong in the renderer's
options object.
Use data APIs for custom rendering
The SVG components provide fixed renderers. Use the hooks or core APIs for custom axes, interaction, Canvas, native charts, or a different accessibility model.
Where React fits in the architecture
Keep normalization, credentials, and long-running data access outside the UI component. A typical application:
- Fetches and normalizes source payloads on the server or data layer.
- Passes
GlucoseReading[]into a client-facing component. - Uses hooks to derive immutable view data.
- Renders that data with its own design system or the optional SVG components.
Follow Build a Glucose Dashboard for a working example.