Skip to content

How Rendering Works ​

This page describes what the questionnaire core does between receiving a questionnaire and returning a submission. Understanding it helps when designing logic in the questionnaire designer, when writing custom question components, and when hosting an engine.

What the engine receives ​

A host starts a session by sending the engine an initialisation message with two things:

PartContents
QuestionnaireThe published questionnaire definition: sections with their questions, per-question settings and translations, the scoring model (variables and functions), the languages block and the engine binding.
Runtime configurationOptions for this particular session: which sections to show, the preferred languages, an optional scoring override, colour mode, zoom level and any engine options the questionnaire's configuration defines.

The host is responsible for choosing the sections (for example, a schedule may deliver only some sections at a given visit) and for passing the patient's language preferences. Everything else comes from the questionnaire definition.

Questions, pages and sections ​

  • A section is an ordered group of questions. The engine flattens the selected sections into one ordered list.
  • A question has a type, a text (per language), a settings object (per language overrides are possible), an optional flag and optional logic (see below).
  • A page is a special question type with no answer: it shows text only, for instructions or a closing message. Pages never block navigation and are not counted in progress or completeness.

Display modes ​

The core supports two display modes, chosen through the engine's runtime options and set per questionnaire in the designer.

ModeBehaviour
PagedOne question at a time with Back and Next buttons and a progress indicator. Logic runs when a question is entered and when it is answered, and may redirect the flow. This is the default and the mode used by the mobile app.
ScrollableAll questions that are reachable on the current path are shown in one scrolling view. The core continuously simulates the path from the first question through the logic, shows exactly the reachable questions, and hides (and clears) the rest.

Lifecycle of a session ​

  1. Ready. The engine mounts, applies colour mode, zoom and text direction, and reports that it is ready.
  2. Enter question. The on_enter logic of the current question runs. It may skip or redirect before the question is shown.
  3. Answer. The question component collects the answer, validates it and reports it to the core together with any validation errors. While a required question has no valid answer, Next stays disabled.
  4. Answer logic. On Next, the on_answer logic runs with the answer in scope. If the logic does not navigate explicitly, the core advances to the next question.
  5. Repeat until the last question is answered or the logic ends the questionnaire early.
  6. Submit. The core assembles the submission (every recorded answer plus the final scoring state) and hands it to the host.
  7. Exit / error. At any time the patient may exit (the host decides how to confirm), and runtime problems are reported to the host as structured errors rather than breaking the session.

Logic: triggers, conditions and actions ​

Questionnaire logic is attached to questions as triggers. A trigger has a condition and two lists of actions: one for when the condition holds and one for when it does not. Triggers are authored visually in the designer (see Logic, Variables & Scoring); the engine evaluates them at runtime.

TriggerWhen it runsHas the answer in scope
on_enterJust before the question is displayedNo
on_answerWhen the patient confirms an answer (Next)Yes

Actions call engine methods. The catalogue below is the complete set a questionnaire can use.

MethodEffect
nextQuestion()Go to the next question; on the last question, submit.
previousQuestion()Go back along the actual navigation history.
skipQuestion()Advance without recording an answer; on the last question, submit.
goToQuestionId(id)Jump to a specific question. If the target is not part of the current session, the engine falls back to the next question and reports an error to the host.
goToQuestionIndex(index)Jump by position. Prefer goToQuestionId.
endQuestionnaire()Submit immediately with the answers collected so far (early termination, screening exclusions).
getQuestionAnswer(id)Read a previously recorded answer.
getQuestionConfig(id)Read a question's effective settings, including language overrides.
getQuestionActions(id)Inspect another question's logic.
getQuestionByName(name)Look a question up by its human-readable name.
getVariable(id) / setVariable(id, value)Read or write a scoring variable by identifier.
getVariableByName(name) / setVariableByName(name, value)Read or write a scoring variable by name.

In scrollable mode the navigation methods are ignored (there is no "current question"); the core instead uses the logic to compute which questions are visible.

Answers ​

Every answer recorded by the core has the same shape regardless of question type:

FieldMeaning
valueThe answer itself: text, number, boolean or a list (for multiple choice).
value_typeOne of string, number, boolean, array. Logic should check the type before comparing.
metaContext added by the component and the core: the language the patient answered in, whether it was the default language, the localised and default question settings, and any component-specific details (for example the index and numeric value of a chosen option).

This uniform shape is what makes scoring, analytics and exports work the same way for built-in and custom question types.

Variables and scoring ​

The questionnaire's scoring model declares variables (typed, with default values) and functions (reusable calculations). Logic reads and writes variables as the patient progresses; the core keeps a scoring snapshot per step in paged mode so that going back and changing an answer produces a consistent result. The final scoring state is included in the submission. See Logic, Variables & Scoring for how these are authored.

Languages ​

Two independent language choices apply to a session:

PreferenceGovernsResolution
Questionnaire languageQuestion text, options, per-language settingsRequested questionnaire language → patient's language → patient's secondary language → browser language → questionnaire default
Interface languageButtons, validation messages, chromePatient's language → browser language → English

The interface ships with ten locales. Right-to-left layout is applied automatically for RTL languages. Custom components receive both preferences and can add their own translations, including overrides supplied per question from the designer.

Presentation ​

AspectBehaviour
Colour modeLight, dark or automatic, as requested by the host (the mobile app follows the patient's setting).
ZoomA percentage that scales all text and controls, for accessibility.
UI componentsThe core bundles a consistent component library (buttons, inputs, sliders, calendars, selects and more) that every question component uses, so custom types look native.
HapticsComponents can request haptic feedback; the host mobile app translates the request into device vibration.
OfflineNo asset is loaded at runtime. Icons, styles and translations are part of the bundle.

Validation ​

Validation lives in the question component. A component reports errors with its answer; the core keeps Next disabled while errors exist or a required question is unanswered. Components can validate on change, on blur or on explicit confirmation, whichever suits the control. The core also provides a JSON Schema validator that components may use for structured checks.