Building Your Workflows on ZapEHR
Forms

Building Forms with ZapEHR

Clinical organization deal with a lot of forms. Anyone who has ever visited a doctor has experienced this. There are forms for gathering patient history, providing consent-to-treat, provider checklists, physical and mental health assessments, and even non-clinical uses like gathering net promoter score post-appointment.

FHIR is particularly well-designed for building forms. In fact, once you are comfortable with the "FHIR way" for form input, you'll find they offer a very easy and rapid way to deliver new functionality because you can often update forms without needing to change code or do deployments.

FHIR Resources

The FHIR Questionnaire (opens in a new tab) resource stores data related to the form itself, including questions and answer options, while QuestionnaireResponse (opens in a new tab) stores actual user responses.

With available extensions (opens in a new tab) Questionnaires can include conditional displays of elements or calculation of score (opens in a new tab) based on responses.

Common workflows

Use the examples below to build some simple patient intake forms. You can edit the input area to change the Questionnaire, and the form will update. The example supports input types of text, number, date, and select, as well as inputs that respond to other inputs — for example try selecting "Other" as a response to "How you learned about us". Of course other input types are available.

This demo includes an example of PHQ-9 (opens in a new tab), a Patient Health Questionnaire often used in healthcare organizations. Patient surveys like the PHQ-9, are one of the most common uses of a Questionnaire.

In real-world ZapEHR use, the user interface gathers form data from the respondent, and the responses are typically stored in ZapEHR using Zambdas. When the user submits the form, your Zambda endpoint validates the input, then stores the responses in a QuestionnaireResponse.

Forms are also applicable for non-medical applications. For example, you can send surveys to patients after an appointment is made. You can create a subscription Zambda to monitor changes to FHIR resources. After a FHIR Appointment (opens in a new tab) is created or the status of an Appointment is fulfilled, the Zambda would send an email to a user with a link to the questionnaire.

National Library of Medicine Form Builder

The National Library of Medicine (NLM) has a website called NLM Form Builder (opens in a new tab) that provides a FHIR form builder. Users can build their own forms, or import forms from various sources. It also has a website for creating forms (opens in a new tab).

Demo

Select one of the following examples, or edit the JSON

Questionnaire:


Form:





The code for this demo takes a list of items into a Questionnaire and creates a form. More complicated forms with dozens of inputs can be written following the same pattern.

const FHIR_TO_HTML_INPUT = {
  string: 'text',
  date: 'date',
};
 
<form>
  {(JSON.parse(questionnaire) as Questionnaire).item
    ?.filter(
      (question) =>
        !question.enableWhen ||
        (question.enableWhen &&
          question.enableWhen[0].operator === '=' &&
          question.enableWhen[0].answerString === values[question.enableWhen[0].question])
    )
    .map((question) => (
      <div style={{ marginBottom: '10px' }}>
        <label htmlFor={question.linkId} style={{ marginRight: '10px' }}>
          {question.text}
        </label>
        {(() => {
          switch (question.type) {
            case 'string':
            case 'date':
              return (
                <input
                  id={question.linkId}
                  name={question.linkId}
                  type={FHIR_TO_HTML_INPUT[question.type]}
                  onChange={(event) => setValues({ ...values, [question.linkId]: event.target.value })}
                ></input>
              );
            case 'choice':
              return (
                <select
                  id={question.linkId}
                  name={question.linkId}
                  onChange={(event) => setValues({ ...values, [question.linkId]: event.target.value })}
                >
                  {question.answerOption?.map((option) => (
                    <option value={option.valueString}>{option.valueString}</option>
                  ))}
                </select>
              );
          }
        })()}
        <br />
      </div>
    ))}
  <button
    type="submit"
    style={{ backgroundColor: '#1acdff', color: 'black', padding: '8px', borderRadius: '5px' }}
  >
    Submit
  </button>
</form>

More Complicated Examples of Form Use

You can build more complicated surveys to fit your needs. Some examples of real-world uses include:

  • Only include certain questions if the survey is being filled out by a legal guardian
  • Automated alerting for certain responses, such as a patient in need of attention
  • Provide the user with a list of nearby pharmacies
  • Ask questions depending on the time of day, such as asking the user if they would like to schedule an appointment if an office is not open