Components / Clinical
Body map
A front and back outline of the body for recording where pain or symptoms are. Each region is a checkbox, so it works with a mouse, a touch screen, a keyboard and a screen reader.
Each view is one tab stop. Arrow keys move between regions; Space or Enter selects or clears the focused region.
1 region selected
Installation
In a project set up as in Installation, run:
bunx shadcn@4.22.1 add https://organui.com/r/body-map.json
Or by name: bunx shadcn@4.22.1 add @organui/body-map.
The source installs into your configured UI directory, along with shadcn's button if you do not have it yet. The body is inline SVG drawn with your theme tokens; there are no images, 3D packages or global styles.
Usage
"use client"
import { useState } from "react"
import { BodyMap } from "@/components/ui/body-map"
export function PainLocation() {
const [regions, setRegions] = useState<string[]>([])
return (
<form action="/symptoms">
<BodyMap
label="Where does it hurt?"
value={regions}
onValueChange={setRegions}
name="regions"
/>
<button type="submit">Save</button>
</form>
)
}Selection is controlled. value is the list of selected region IDs in the order they were picked, and onValueChange receives the next list. IDs that are not among the regions are dropped from that list. With name, each selected ID is submitted as a hidden input, so a plain form posts regions=right-knee®ions=….
Sides are the patient's. From the front, the patient's right is on the viewer's left; from the back it is on the viewer's right. Small R and L markers beside each view say so. Front and back regions have separate IDs, such as right-knee and right-knee-back.
Keyboard and screen readers
Each view is one tab stop. Arrow keys move to the nearest region in that direction, Home and End jump to the first and last region, and Space or Enter selects or clears the focused region. Regions are announced by name with their checked state, and a status line counts the selection. Selected regions are also listed as buttons that remove them, which is the quickest way to undo a pick on a small screen.
Customize
import { BodyMap, bodyMapRegions } from "@/components/ui/body-map"
// Translate labels, or drop regions you do not record.
const regions = bodyMapRegions
.filter(({ view }) => view === "front")
.map((region) => ({ ...region, label: translate(region.label) }))
<BodyMap regions={regions} views={["front"]} value={value}
onValueChange={(ids) => setValue(ids.slice(-1))} />bodyMapRegions exports the default regions. Pass your own list to regions to rename, remove or redraw them; paths share a 200 by 440 coordinate space and paired shapes set mirrored to reflect across the midline. Use views to show one side, label for the group's accessible name and className for the outer container. To allow one region only, keep the last ID as shown above. Edit the installed source to shade regions by severity.
The outline and regions were drawn for this component as a simplified, non-clinical diagram. They do not follow a validated pain-drawing instrument or dermatome boundaries.