- Accordion
- Alert
- Alert Dialog
- Avatar
- Badge
- Button
- Calendar
- Card
- Carousel
- Chart
- Checkbox
- Circular Progress
- Collapsible
- Compare Slider
- Dialog
- Dropdown Menu
- Gauge
- Input
- Label
- Marquee
- Navigation Menu
- Number Field
- Pagination
- Popover
- Progress
- Radio Group
- Scroll Area
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Switch
- Table
- Tabs
- Textarea
- Toggle
- Tooltip
Demos
Enter a date of birth. "Measured on" starts on today.
- Chronological
- —
- Corrected
- —
- Completed years
- —
"use client"
import { AgeCalculator } from "@workspace/ui/tools/age-calculator"
export function AgeCalculatorDemo() {
return (
<div className="mx-auto flex w-full justify-center">
<AgeCalculator />
</div>
)
}
Usage
Use the age calculator wherever a result depends on age, such as a growth chart or a reference range. It shows three ages:
- Chronological — Months since birth, in WHO months of 30.4375 days. From 24 months it shows years and months, such as
3 y 2 mo. - Corrected — Chronological age less the weeks born before term (40 weeks). Never below zero.
- Completed years — Age as a birthday counts it. Someone born on 29 February has their birthday on 1 March in other years.
Import it from @workspace/ui/tools/age-calculator.
Notes
- Growth charts use corrected age for babies born before 37 weeks, usually until 24 months. For a baby born at term, leave "Born at" on 40 and both ages match.
- "Born at" takes 22 to 42 weeks. Clearing it goes back to 40. Over 40 weeks makes no correction.
- Dates are read as UTC midnight, so the result is the same in every time zone.
- The reset button goes back to the default dates and weeks.
Age helpers
The maths is in @workspace/ui/lib/age, so you can use it without the UI.
calculateAge(birth, measured, gestationalWeeks) from the component file returns all three at once, or null when the measurement date is before the date of birth.
Examples
Born early
A baby born at 32 weeks, measured at 11 months. Eight weeks come off, so the corrected age is 9.5 months.
- Chronological
- 11.3 months
- Corrected
- 9.5 months
- Completed years
- 0
"use client"
import { AgeCalculator } from "@workspace/ui/tools/age-calculator"
export function AgeCalculatorDefault() {
return (
<div className="mx-auto flex w-full justify-center">
<AgeCalculator
defaultBirthDate={new Date(2025, 1, 10)}
defaultMeasuredDate={new Date(2026, 0, 20)}
defaultGestationalWeeks={32}
/>
</div>
)
}
Listen for changes
Pass onChange to get the result each time an input changes. You get null when no result can be worked out.
- Chronological
- 11.3 months
- Corrected
- 11.3 months
- Completed years
- 0
onChange: null
"use client"
import * as React from "react"
import {
AgeCalculator,
type AgeResult,
} from "@workspace/ui/tools/age-calculator"
export function AgeCalculatorOnChange() {
const [result, setResult] = React.useState<AgeResult | null>(null)
return (
<div className="mx-auto flex w-full flex-col items-center gap-3">
<AgeCalculator
defaultBirthDate={new Date(2025, 1, 10)}
defaultMeasuredDate={new Date(2026, 0, 20)}
onChange={setResult}
/>
<p className="text-xs text-muted-foreground">
{result
? `onChange: ${result.ageMonths.toFixed(2)} months, ${result.completedYears} completed years`
: "onChange: null"}
</p>
</div>
)
}
Props
Unlisted props pass through to the Card that wraps the calculator.
AgeCalculator
| Prop | Type | Default | Description |
|---|---|---|---|
defaultBirthDate | Date | — | Date of birth on first render and after reset. |
defaultMeasuredDate | Date | today | Measurement date on first render and after reset. |
defaultGestationalWeeks | number | 40 | Weeks of pregnancy at birth. |
onChange | (result: AgeResult or null) => void | — | Called when the result changes. |
className | string | — | Classes merged onto the card. |
AgeResult
| Field | Type | Description |
|---|---|---|
ageMonths | number | Chronological age in WHO months. |
correctedAgeMonths | number | Age in months corrected for prematurity. |
completedYears | number | Completed years. |
Pass any month value to formatAge to show it as text.