bio-checkin
<bio-checkin>
A patient-reported outcome (PRO) check-in widget that presents a step-by-step questionnaire and submits responses as observations. Supports both static configuration (via attributes) and profile-driven mode (auto-configured from the user's episode profile).
<bio-checkin question-types='["readiness","confidence","worry"]'></bio-checkin>How It Works
When <bio-checkin> receives context from a parent <bio-provider>:
- Resolves configuration — in profile-driven mode, reads question types, schedule, and questionnaire ID from the SDK config; in static mode, parses the
question-typesattribute - Fetches prior scores — calls
GET /api/v1/observations/latestfor each biosignal to show the user's last response - Presents questions one at a time — renders a scale (1–5 or 1–10 depending on question type) with step counter
- Submits all answers — sends a single
POST /api/v1/episodes/:id/questionnaire-responsecontaining all items - Shows results with trends — the server compares each answer to the most recent prior observation and returns a trend (
increasing,decreasing, orstable) - Supports updates — an "Update" button lets the user re-submit, and the next trend comparison will use the previous submission as the baseline
Modes
Static Mode
Pass question types directly as an attribute. You control which questions appear:
<bio-checkin
question-types='["readiness","confidence"]'
episode-id="ep_abc123">
</bio-checkin>Profile-Driven Mode
Omit question-types and let the widget auto-configure from the user's episode profile. The profile's spec.sdk.checkin section defines available check-in contexts (e.g., weekly, daily), each with its own question types, schedule, and questionnaire ID.
<bio-checkin context_type="weekly"></bio-checkin>In profile-driven mode, the widget also reads the check-in status from the SDK config. If the check-in is already completed for the current period, it renders a summary view instead of the questionnaire form.
Attributes
| Attribute | Type | Required | Description |
|---|---|---|---|
question-types | string | No | JSON array of question type strings (e.g., '["sleep","mood","energy"]'). Omit for profile-driven mode. |
episode-id | string | No | Episode ID for submission. Falls back to the episode resolved by <bio-provider>. |
questionnaire-id | string | No | Questionnaire identifier. Defaults to "default". Overridden by profile config in profile-driven mode. |
context_type | string | No | Check-in context key (e.g., "weekly", "daily"). In profile-driven mode, selects which check-in config to use. |
Events
| Event | Detail | Description |
|---|---|---|
anybio:checkin:submit | { eventId, questionnaireId, observations, episodeId, context } | Fired after successful submission. observations is an array of created observation objects including value_quantity, trend, and prior_value. |
anybio:checkin:error | { error: string } | Fired if submission fails. |
anybio:checkin:dismiss | {} | Fired when the user closes the check-in overlay without completing. |
bio-checkin-complete | (same as anybio:checkin:submit) | Backward-compatible alias. |
bio-checkin-error | (same as anybio:checkin:error) | Backward-compatible alias. |
bio-checkin-dismiss | (same as anybio:checkin:dismiss) | Backward-compatible alias. |
Trend Indicators
After submission, each result row can display a trend arrow comparing the current score to the most recent prior observation for that biosignal:
| Trend | Symbol | Color Variable |
|---|---|---|
increasing | ↑ | --bio-trend-improving (green) |
decreasing | ↓ | --bio-trend-declining (red) |
stable | = | --bio-trend-stable (gray) |
| no prior data | (hidden) | — |
Trends are computed server-side in the questionnaire-response handler. When no prior observation exists, the trend field is null and no indicator is shown.
CSS Classes
The widget renders with semantic CSS classes for styling. No Shadow DOM — standard CSS selectors work.
| Class | Element |
|---|---|
.bio-checkin-overlay | Full-screen backdrop (static mode) |
.bio-checkin-modal | Modal card |
.bio-checkin-header | Step counter + close button row |
.bio-checkin-step | "1 of 3" step text |
.bio-checkin-close | Close (×) button |
.bio-checkin-question | Question heading |
.bio-checkin-prior | "Last time: 7/10" prior score |
.bio-checkin-scale | Scale button container |
.bio-checkin-scale-btn | Individual scale button (1–10) |
.bio-checkin-labels | Low/High labels |
.bio-checkin-summary | Completed summary card |
.bio-checkin-results | Results list |
.bio-checkin-result-item | Individual result row |
.bio-checkin-score | Score value |
.bio-checkin-trend | Trend indicator (↑/↓/=) |
.bio-checkin-submitted-at | Timestamp |
.bio-checkin-update-btn | "Update" button |
.bio-checkin-done-btn | "Done" button (static mode) |
CSS Custom Properties
| Property | Default | Description |
|---|---|---|
--bio-primary | #5a8a6a | Score and heading accent color |
--bio-surface | #ffffff | Card/modal background |
--bio-surface-muted | #f8fafc | Result row background |
--bio-border | #e2e8f0 | Scale button border |
--bio-radius | 8px | Border radius for result items |
--bio-radius-lg | 12px | Border radius for cards |
--bio-shadow-md | — | Summary card shadow |
--bio-shadow-lg | — | Modal shadow |
--bio-trend-improving | #22c55e | Increasing trend color |
--bio-trend-stable | #64748b | Stable trend color |
--bio-trend-declining | #ef4444 | Decreasing trend color |
Code Examples
Profile-Driven Weekly Check-in
<bio-provider
api-key="org_your_key"
project-key="proj_your_key"
xuser-id="user-123">
<bio-checkin context_type="weekly"></bio-checkin>
</bio-provider>The widget reads the weekly entry from the profile's spec.sdk.checkin map. If the user has already completed the weekly check-in, it shows the summary with scores and trends. Otherwise it opens the questionnaire.
With Event Handling
<bio-checkin id="checkin" context_type="weekly"></bio-checkin>
<script>
document.addEventListener('anybio:checkin:submit', (e) => {
const { observations, episodeId } = e.detail;
observations.forEach(obs => {
console.log(`${obs.biosignal}: ${obs.value_quantity} (${obs.trend})`);
});
});
document.addEventListener('anybio:checkin:dismiss', () => {
console.log('Check-in dismissed');
});
</script>Custom Styling
/* Match your app's design system */
bio-checkin {
--bio-primary: #1a73e8;
--bio-radius-lg: 16px;
--bio-trend-improving: #34a853;
--bio-trend-declining: #ea4335;
}
/* Style the scale buttons */
.bio-checkin-scale-btn {
width: 48px;
height: 48px;
}
/* Customize the summary card */
.bio-checkin-summary {
border: 1px solid var(--bio-border);
}Static Mode with All Options
<bio-checkin
question-types='["readiness","confidence","worry","energy","pain"]'
episode-id="ep_abc123"
questionnaire-id="pre_op_weekly">
</bio-checkin>Roadmap
- Submission cooldown — Wire up the backend policy cooldown system to enforce frequency limits (e.g., one weekly check-in per 7-day window). The infrastructure exists in the policy engine; it needs to be connected to the questionnaire-response endpoint.