Purpose
This article explains how to build custom patient questionnaires using the Medicus XML schema. Custom questionnaire XML lets you define form fields, conditional logic, and care record filing codes in a structured file, which you can paste directly into a questionnaire template version in the Content Hub.
If you are not familiar with XML, we recommend using the questionnaire builder UI instead. The XML schema is intended for developers or users who are comfortable working programmatically.
You are responsible for ensuring the validity of your questionnaires and any clinical implications associated with their content.
How to write questionnaires XML
There are two ways to write questionnaires XML. The first is manually, using a text editor such as VS Code. The second is using an AI tool such as Claude - pass the XSD (attached at the bottom of this article) along with a plain-English description of your questionnaire. AI tools are increasingly capable of generating valid XML from a schema.
Once your XML is ready, paste it into the Edit version content field of a draft questionnaire template in Modules > Communication > Patient Questionnaire Templates.
Questionnaire structure
Every questionnaire is wrapped in a <patientQuestionnaire> root element with a fixed version="2.0" attribute. Inside it, there are three top-level elements: <documentCode>, an optional <additionalFilingCodes> block, and a <form>.
<patientQuestionnaire version="2.0">
<documentCode code="182836005"/>
<additionalFilingCodes>...</additionalFilingCodes>
<form>
<title>...</title>
<description>...</description>
<!-- form fields go here -->
</form>
</patientQuestionnaire>
Document code
The <documentCode> element sets the primary SNOMED CT code filed to the patient's care record when the questionnaire is submitted. The code attribute is required and must be a valid SNOMED CT concept ID (minimum six digits).
<documentCode code="182836005"/>
Additional filing codes
The optional <additionalFilingCodes> block lets you file extra entries to the care record on submission, independently of any conditional logic on individual fields. You can include any combination of care record notes, allergy or intolerance entries, and observations.
<additionalFilingCodes>
<careRecordNote code="408731000" note="Structured education offered"/>
<careRecordObservation code="271649006" unitOfMeasure="259018001"/>
</additionalFilingCodes>
See Care record entry types for the full reference on these elements.
Form
The <form> element defines everything the patient sees. It requires a <title> and accepts an optional <description>. All form fields are placed inside it, in any order.
<form>
<title>Diabetes Annual Review</title>
<description>Please answer the following questions before your appointment.</description>
<!-- form fields -->
</form>
Form fields
All form fields share three common attributes:
- name — a unique identifier for the field (required). Must start with a letter and contain only letters, numbers, and underscores.
- label — the text shown to the patient above the field.
- required — set to true to make the field mandatory before submission.
The sections below describe each field type and any additional attributes or child elements they support.
Checkbox
A single tick-box option. Use for yes/no or opt-in questions.
- text — the label displayed next to the checkbox (required).
- value — the value stored when checked (required).
- Optionally contains an <ifChecked> child element to file a care record entry when ticked. See Conditional filing.
<checkbox name="smoker" label="Smoking status" text="I am a current smoker" value="yes" required="true">
<ifChecked>
<careRecordNote code="77176002"/>
</ifChecked>
</checkbox>
Checkbox group
A set of tick-box options where the patient can select multiple answers. Each option is defined with a <checkboxOption> child element.
- twoColumns — set to true to display the options in two columns.
- Each <checkboxOption> requires a label and a value. Values must be unique within the group.
- Each <checkboxOption> optionally contains an <ifChecked> child element.
<checkboxGroup name="symptoms" label="Current symptoms" twoColumns="true">
<checkboxOption label="Fatigue" value="fatigue"/>
<checkboxOption label="Blurred vision" value="blurred_vision">
<ifChecked>
<careRecordNote code="246636008"/>
</ifChecked>
</checkboxOption>
</checkboxGroup>
Radio group
A set of options where the patient can select only one answer. Each option is defined with a <radioOption> child element.
- Each <radioOption> requires a label and a value. Values must be unique within the group.
- Each <radioOption> optionally contains an <ifSelected> child element. See Conditional filing.
<radioGroup name="diet" label="How would you describe your diet?">
<radioOption label="Healthy" value="healthy"/>
<radioOption label="Could be improved" value="moderate"/>
<radioOption label="Poor" value="poor">
<ifSelected>
<careRecordNote code="408580006"/>
</ifSelected>
</radioOption>
</radioGroup>
Select
A dropdown list where the patient selects one option. Each option is defined with a <selectOption> child element.
- Each <selectOption> requires a label and a value. Values must be unique within the select.
- Each <selectOption> optionally contains an <ifSelected> child element.
<select name="ethnicity" label="Ethnicity">
<selectOption label="White British" value="white_british"/>
<selectOption label="Asian or Asian British" value="asian"/>
<selectOption label="Black or Black British" value="black"/>
</select>
Text input
A single-line free-text field. Optionally contains an <ifTextSet> child element to file a care record note when the patient enters any text. See Conditional filing.
<textInput name="concerns" label="Any concerns you'd like to discuss?">
<ifTextSet>
<careRecordNote code="401251002"/>
</ifTextSet>
</textInput>
Textarea
A multi-line free-text field. Behaves identically to <textInput> but gives the patient more space for longer responses. Also supports an optional <ifTextSet> child element.
<textarea name="history" label="Describe any recent symptoms"/>
Quantity
A numeric input field. Supports optional minValue and maxValue attributes to constrain the accepted range. Optionally contains an <ifValueSet> child element to file an observation when a value is entered. See Conditional filing.
<quantity name="weight" label="Weight (kg)" minValue="20" maxValue="300" required="true">
<ifValueSet>
<careRecordObservation code="27113001" unitOfMeasure="258683005"/>
</ifValueSet>
</quantity>
Date input
A date picker field. Supports optional minDate and maxDate attributes (in YYYY-MM-DD format) to restrict the selectable range. Optionally contains an <ifValueSet> child element.
<dateInput name="last_review" label="Date of last review" maxDate="2025-05-20"/>
Time
A time picker field. Takes only the common name, label, and required attributes. It has no additional attributes or child elements.
<time name="appointment_time" label="Preferred appointment time"/>
Blood pressure
A paired systolic/diastolic blood pressure input. Unlike other fields, the <ifValueSet> child element is required (not optional), so that a reading is always filed to the care record when entered.
Supports optional minValue, maxValue, and decimalPlaces attributes.
<bloodPressure name="bp_reading" label="Blood pressure" required="true">
<ifValueSet>
<careRecordObservation code="75367002"/>
</ifValueSet>
</bloodPressure>
Info banner
A display-only element, not a form field. Use it to show guidance text or contextual information to the patient within the form. It does not collect or file any data.
- title — a heading displayed above the banner text.
- text — the body text of the banner.
<infoBanner title="About this questionnaire" text="Your answers will be shared with your GP before your appointment."/>
Conditional filing
Conditional filing elements let you file entries to the patient's care record based on how they respond to a specific question. They are placed as child elements inside the relevant field.
<ifChecked> — used inside <checkbox> and <checkboxOption>. Files a care record entry when the option is ticked. Supports <careRecordNote> or <careRecordAllergyIntolerance>.
<ifSelected> — used inside <radioOption> and <selectOption>. Files a care record entry when the option is selected. Supports <careRecordNote> or <careRecordAllergyIntolerance>.
<ifTextSet> — used inside <textInput> and <textarea>. Files a care record note when the patient enters any text. Supports <careRecordNote> only.
<ifValueSet> — used inside <quantity>, <dateInput>, and <bloodPressure>. Files an observation when the patient enters a value. Supports <careRecordObservation> only. Required (not optional) for <bloodPressure>.
Care record entry types
careRecordNote
Files a coded note to the patient's care record.
- code — a SNOMED CT concept ID (required).
- note — a plain-text annotation added to the filed entry (optional).
<careRecordNote code="77176002" note="Confirmed by patient self-report"/>
careRecordAllergyIntolerance
Files an allergy entry to the patient's care record.
- code — a SNOMED CT concept ID (required).
<careRecordAllergyIntolerance code="372687004"/>
careRecordObservation
Files a coded observation, such as a measurement or test result.
- code — a SNOMED CT concept ID (required).
- unitOfMeasure — a SNOMED CT concept ID representing the unit (optional, but recommended for numeric fields).
<careRecordObservation code="27113001" unitOfMeasure="258683005"/>
Example questionnaire
The following example shows a short pre-appointment questionnaire for a diabetes review. It demonstrates a range of field types, conditional filing, and an additional filing code on submission.
<patientQuestionnaire version="2.0">
<documentCode code="314529007"/>
<additionalFilingCodes>
<careRecordNote code="408731000" note="Pre-appointment questionnaire completed"/>
</additionalFilingCodes>
<form>
<title>Diabetes Review — Pre-appointment Questionnaire</title>
<description>Please complete this short questionnaire before your appointment. Your answers will be shared with your care team.</description>
<infoBanner title="About this form" text="This should take around 5 minutes to complete."/>
<radioGroup name="overall_health" label="How would you rate your overall health over the past 3 months?" required="true">
<radioOption label="Good" value="good"/>
<radioOption label="Fair" value="fair"/>
<radioOption label="Poor" value="poor">
<ifSelected>
<careRecordNote code="248268008"/>
</ifSelected>
</radioOption>
</radioGroup>
<quantity name="weight" label="Current weight (kg)" minValue="30" maxValue="300" required="true">
<ifValueSet>
<careRecordObservation code="27113001" unitOfMeasure="258683005"/>
</ifValueSet>
</quantity>
<bloodPressure name="bp" label="Blood pressure reading" required="true">
<ifValueSet>
<careRecordObservation code="75367002"/>
</ifValueSet>
</bloodPressure>
<checkboxGroup name="symptoms" label="Have you experienced any of the following in the past month?">
<checkboxOption label="Excessive thirst" value="thirst"/>
<checkboxOption label="Blurred vision" value="blurred_vision">
<ifChecked>
<careRecordNote code="246636008"/>
</ifChecked>
</checkboxOption>
<checkboxOption label="Foot pain or numbness" value="foot_pain"/>
</checkboxGroup>
<textarea name="concerns" label="Is there anything else you would like to discuss at your appointment?"/>
</form>
</patientQuestionnaire>
XML schema
The XSD schema file is attached to the bottom of this article. You can use it to validate your XML before pasting it into the questionnaire builder, or pass it to an AI tool to help generate questionnaire XML.
FAQs
Q: What happens if my XML is invalid?
A: The questionnaire builder will surface a validation error when you attempt to save the content. We recommend validating your XML against the attached XSD before pasting it in.
Q: Can I use an AI tool to generate questionnaire XML?
A: Yes, tools such as Claude work well for this. Attach the XSD from the bottom of this article and describe your questionnaire in plain English. Always review the output before using it clinically.
Q: Can I edit the XML after the template version has been published?
A: No. XML content can only be edited while the template version has a status of Draft. Once a version is active, it cannot be modified. To make changes, create a new version of the template.