Building a User Interface

Recommended UI patterns for rendering questions - messages, choices, symptom definitions, constraints, and the autocomplete search

The API is schema-driven: every question arrives with display messages, selectable choices, and selection constraints, and a well-built client renders from those fields generically. This page shows the recommended UI pattern for each element. For the underlying data contract — field-by-field definitions and how to construct answers — see Questions & Answers.

Messages

Messages are the text component of a question. The API can return one or more per question — render all of them, in the order they are returned, each on its own line.

They arrive as question.messages[], standard Message objects: value is the text to display, type is a placement hint (header, paragraph, bullet point…), and format tells you whether to render it as plain text or markdown.

Choices

Choices are returned in an array; there is always at least one. For each choice, text is what you display and id is what you send back in the answer.

Symptom definitions

A choice may also carry a symptom_definition — a plain-language explanation of the symptom, as a standard Message:

{
  "id": "C0041105",
  "text": "Ringing in the ears",
  "symptom_definition": {
    "value": "A perception of sound (often ringing or buzzing) without an external source.",
    "type": "PARAGRAPH",
    "format": "PLAIN_TEXT"
  }
}

Definitions are per choice: each one explains only the choice it is attached to, so render it with that choice — as supporting text under the label, or behind an info icon/expandable next to it. Respect its format like any other Message. Choices without a definition simply omit the field, so a list can mix choices with and without one.

Constraints

The constraints object has two properties, min_selections and max_selections, and together they tell you which input control to build. The combinations:

Minimum 1 — Maximum 1

Mandatory single choice: render the choices as radio buttons, and don't allow continuing without a selection.

Minimum 0 — Maximum n

Optional multi-select: render the choices as checkboxes.

Note the None of these choice in the example below. Add a client-side "None of the above" only when min_selections is 0 (or missing). Selecting it clears other selections and sends every id in excluded (see the answer rules). Keep Continue disabled until the user selects a choice or "None of the above" — the Implementation Guidelines require this forced choice.

Some questions already include "None of these", "Don't know" or "Prefer not to say" as normal choices from the API. Render them like any other choice and don't add your own.

Minimum 1 — Maximum n

Mandatory multi-select: render the choices as checkboxes, with no way to continue until at least one is selected.

Either bound may be absent — treat a missing min_selections as 0 and a missing max_selections as unlimited.

Autocomplete

The autocomplete question type is the one place a generic choice renderer isn't enough: the user searches our symptom database and adds symptoms to the consultation. The question looks like:

"question": {
    "type": "autocomplete",
    "messages": [
        {
            "value": "OK, please tell me what symptoms you would like to add",
            "type": "HEADER",
            "format": "PLAIN_TEXT"
        },
        {
            "value": "You can add a maximum of 4 symptoms altogether, including those you may have already selected before.",
            "type": "PARAGRAPH",
            "format": "PLAIN_TEXT"
        },
        {
            "value": "Type your symptoms…",
            "type": "INPUT_HINT",
            "format": "PLAIN_TEXT"
        }
    ],
    "constraints": {
        "min_selections": 0,
        "max_selections": 3
    }
}

How many symptoms may be sent in one answer is governed by constraints.min_selections/max_selections, like any other question — treat the message copy as display text only. max_selections already accounts for the symptoms in the assessment (4 in total), so in the example above the user has 1 symptom and can add up to 3.

This step only adds symptoms. Symptoms already in the assessment are in conversation_details.symptoms_summary.selected; if you show them, make them read-only. Symptoms the user has picked from search but not yet submitted can be removed in your UI. Send only included — excluded is rejected for autocomplete.

For this screen, our UI recommendation is a search box that calls the symptom search endpoint:

While no symptom has been added, show a button that lets the user skip this step. To signal that nothing was added, answer with the literal id skip_autocomplete:

{
    "type": "autocomplete",
    "included": ["skip_autocomplete"]
}


Once the user has selected at least one additional symptom, replace it with an Add these symptoms button and respond with the ids of the newly added symptoms (respecting the question's constraints):

{
    "type": "autocomplete",
    "included": ["assessment_C2316035"]
}

Copy your UI supplies

The API provides all question copy. Your UI supplies:

  • Button labels: Next, None of the above, Skip this step, Add these symptoms.
  • The technical fault screen and modal — the approved copy is in the Implementation Guidelines (section 2.13). Error responses carry no user-facing text (see Errors, Limits & Timeouts).
  • The invalid-age message, built from age_question.constraints (returned by POST /terms).

What’s Next

Did this page help you?