On this page ⌄
Tutorial · Clinical Questionnaire Authoring and Extraction
Author standard Structured Data Capture questionnaires, evaluate real-time FHIRPath validation rules, and extract clinical resources.
Overview
In this tutorial, you will design, render, and process a clinical intake questionnaire using the Structured Data Capture (SDC) standard and Jetpack Compose Multiplatform.
You will learn how to build nested form items, apply dynamic calculations with FHIRPath, render forms on device, and extract Observation resources automatically upon form submission.
Prerequisites
- Completed the Multiplatform Client Codelab or have an existing Kotlin Multiplatform project
kotlin-fhir-data-captureimported in your project
Step 1 · Define a Questionnaire resource
Create a standard FHIR Questionnaire resource with validation constraints and choice sets.
{
"resourceType": "Questionnaire",
"id": "vitals-check",
"status": "active",
"item": [
{
"linkId": "systolic",
"text": "Systolic Blood Pressure (mmHg)",
"type": "integer",
"required": true
},
{
"linkId": "diastolic",
"text": "Diastolic Blood Pressure (mmHg)",
"type": "integer",
"required": true
}
]
}
Step 2 · Add real-time FHIRPath validation
Embed dynamic calculate and enableWhen expressions to enforce clinical constraints directly on device.
{
"linkId": "stage-warning",
"text": "Elevated blood pressure detected",
"type": "display",
"extension": [
{
"url": "http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression",
"valueExpression": {
"language": "text/fhirpath",
"expression": "%resource.item.where(linkId='systolic').answer.value > 140"
}
}
]
}
Step 3 · Render the questionnaire in Compose
Render the questionnaire dynamically with Jetpack Compose Multiplatform.
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import dev.ohs.fhir.datacapture.Questionnaire
import dev.ohs.fhir.model.r4.QuestionnaireResponse
import kotlinx.coroutines.launch
@Composable
fun ClinicalIntakeScreen(
questionnaireJson: String,
handleFormSubmission: (QuestionnaireResponse) -> Unit,
) {
val scope = rememberCoroutineScope()
Questionnaire(
questionnaireJson = questionnaireJson,
onSubmit = { getResponse ->
scope.launch {
val response = getResponse()
handleFormSubmission(response)
}
},
)
}
Step 4 · Extract clinical Observation resources
Use template-based extraction to generate structured FHIR Observation records from the completed QuestionnaireResponse.
import dev.ohs.fhir.datacapture.mapping.TemplateExtractionEngine
import dev.ohs.fhir.model.r4.Bundle
// Extract structured resources using embedded Questionnaire templates
val canExtract = TemplateExtractionEngine.canExtract(questionnaire)
if (canExtract) {
val transactionBundle: Bundle = TemplateExtractionEngine.extract(
questionnaire = questionnaire,
questionnaireResponse = response,
)
}
Where to go next
- Learn how to visualize clinical indicators in the SQL-on-FHIR Analytics Tutorial.
- Review Kotlin FHIR Data Capture documentation.