Skip to main content

Writing your own schema

warning

RehabAlpha is still under active development. It is not yet HIPAA compliant and should only be used with dummy data.

Note

This guide assumes you've already set up a therapy company in RehabAlpha. Furthermore, we assume you're signed in to that company with Owner or Admin access. Custom access does not include schema administration.

Schemas can look intimidating at first, but the core idea is simple:

A schema tells RehabAlpha:

  • what fields to show
  • how to organize them
  • when to show them
  • which template to use for each document type

If you are new to schemas, the best approach is to start with something very small, make sure it works, and then build up from there.


Your first schema​

Let’s start with the smallest useful example: one evaluation template with one text node. Copy the schema below.

{
"id": "my_first_evaluation_template",
"type": "template",
"label": "My Evaluation Template",
"appliesTo": "evaluation",
"children": ["heck_yeah_text"]
}

{
"id": "heck_yeah_text",
"type": "text",
"value": "Heck yeah!"
}

Now, go to the Schema page (under Organization > Schema in the sidebar). Replace the existing, default schema in the editor with the one above. Then click Save.

Next, open a therapy case for a dummy patient that does not have a saved evaluation, then click New evaluation. In Custom data template, select My Evaluation Template. Keep the evaluation unsaved while working through these examples so you can reload it after each schema change.

Once selected, a new section should appear with some text that says "Heck yeah!".

Congrats! πŸ₯³ You've successfully deployed your first schema. πŸŽ‰πŸŽ‰πŸŽ‰


How It Worked​

Let's break down exactly what you just copy-pasted.

A schema in RehabAlpha is just a list of building blocks. We call these blocks "nodes".

Every single node requires two things:

  1. id: A unique name you give the node so the system can keep track of it (like "heck_yeah_text"). It can't have spaces!
  2. type: Tells the system what kind of node this is (like "text", "textInput", or "template").

In our stupidly simple example, we created two nodes:

  • The Template Node: Think of this as the root of a tree. We set "appliesTo": "evaluation" so RehabAlpha knows this template belongs in the evaluation form. The "children" array tells RehabAlpha which other nodes to include in this template. Here, we told it to include the node with the ID "heck_yeah_text".

    {
    "id": "my_first_evaluation_template",
    "type": "template",
    "label": "My Evaluation Template",
    "appliesTo": "evaluation",
    "children": ["heck_yeah_text"]
    }
  • The Text Node: This node just displays static text on the screen.

    {
    "id": "heck_yeah_text",
    "type": "text",
    "value": "Heck yeah!"
    }

Adding comments​

Schemas support inline and block comments, so you can annotate your schemas with helpful notes. For example, we could add the following comments to our schema..

/**
* Here we create a template that applies to the evaluation form.
* For now, it'll have one child node - a text node, that displays "Heck yeah!"
*/
{
"id": "my_first_evaluation_template", // This is the node's unique identifier
"type": "template", // This is a template node
"label": "My Evaluation Template", // This label will appear in the template drop down list
"appliesTo": "evaluation", // This template will appear as an option in the evaluation form
"children": ["heck_yeah_text"] // These nodes are included in this template
}

/**
* Here we create a text node that displays "Heck yeah!"
* It's referenced by the template node above.
* In the future, this node could be referenced by other nodes as well.
*/
{
"id": "heck_yeah_text", // This is the node's unique identifier
"type": "text", // This is a text node
"value": "Heck yeah!" // This is the text that will appear on screen
}

Leveling Up: Collecting Real Data​

Showing text is cool, but forms are supposed to collect data. Let's add an actual input field to our schema. Go back to Organization > Schema and update your schema to look like this:

{
"id": "my_first_evaluation_template",
"type": "template",
"label": "My Evaluation Template",
"appliesTo": "evaluation",

// The template's children now references two nodes!
"children": ["heck_yeah_text", "chief_complaint_input"]
}

// Nothing new here...
{
"id": "heck_yeah_text",
"type": "text",
"value": "Heck yeah!"
}

// This is our new node!
{
"id": "chief_complaint_input",
"type": "textInput",
"label": "Chief Complaint",
"placeholder": "Enter the primary reason for therapy...",
"tooltip": "Describe the primary reason for this evaluation.",
"isRequiredToSave": true
}

Save the schema, then reload the unsaved evaluation. Select My Evaluation Template in Custom data template. You should now see a text box!

Note

Saving a schema creates a new active schema version. New clinical documents use the active schema. A saved clinical document keeps its selected schema and template when reopened. Reload an unsaved evaluation to preview the latest version; therapy cases do not store schema or template selections.


Refining Inputs: Placeholders, Tooltips, and Validation​

Right now, our Chief Complaint text box is a little plain, and the user could easily accidentally save the form without typing anything into it. Let's make it better by adding three new properties to our chief_complaint_input node: placeholder, tooltip, and isRequiredToSave.

{
"id": "chief_complaint_input",
"type": "textInput",
"label": "Chief Complaint",
"placeholder": "Enter the primary reason for therapy...", // Gives the user a hint
"tooltip": "Describe the primary reason for this evaluation.", // Tells the user about this field
"isRequiredToSave": true // Prevents saving the form if this is empty
}
  • placeholder: This adds gray, ghosted text inside the input box before the user types anything. It’s perfect for giving examples of what kind of data you expect.
  • tooltip: This adds a helpful note, describing the field to the clinician/user when they hover over the tooltip icon ⍰
  • isRequiredToSave: Setting this to true enforces validation. The clinician will not be able to save their draft until they provide an answer for this field.
See the full schema at this stage
// === Template nodes ======================================

{
"id": "my_first_evaluation_template",
"type": "template",
"label": "My Evaluation Template",
"appliesTo": "evaluation",
"children": ["heck_yeah_text", "chief_complaint_input"]
}

// === Input nodes ======================================

{
"id": "heck_yeah_text",
"type": "text",
"value": "Heck yeah!"
}

{
"id": "chief_complaint_input",
"type": "textInput",
"label": "Chief Complaint",
"placeholder": "Enter the primary reason for therapy...",
"tooltip": "Describe the primary reason for this evaluation.",
"isRequiredToSave": true
}

Ordering the fields​

Have you noticed how the "heck_yeah_text" appears above the "chief_complaint_input" in your form? That’s not random. The order the fields render on the screen is strictly determined by the order of IDs in your template's "children" array.

If you want the input to appear before the text, simply swap their order in the array:

{
"id": "my_first_evaluation_template",
"type": "template",
"label": "My Evaluation Template",
"appliesTo": "evaluation",

// chief_complaint_input is now first!
"children": ["chief_complaint_input", "heck_yeah_text"]
}

Update your schema with this swapped array, save it, and check your form. The input box will now be sitting comfortably at the top.

See the full schema at this stage
// === Template nodes ======================================

{
"id": "my_first_evaluation_template",
"type": "template",
"label": "My Evaluation Template",
"appliesTo": "evaluation",
"children": ["chief_complaint_input", "heck_yeah_text"]
}

// === Input nodes ======================================

{
"id": "heck_yeah_text",
"type": "text",
"value": "Heck yeah!"
}

{
"id": "chief_complaint_input",
"type": "textInput",
"label": "Chief Complaint",
"placeholder": "Enter the primary reason for therapy...",
"tooltip": "Describe the primary reason for this evaluation.",
"isRequiredToSave": true
}

Expanding Our Toolkit: More Input Types​

A single-line text box is great, but therapy documentation requires a variety of data types. Let's introduce three more essential input nodes to our form:

1. The Text Area (textAreaInput)​

Sometimes you need more room to type. A textAreaInput works exactly like a textInput, but it supports multiple lines and auto-expands as the user types. Perfect for clinical narratives!

{
"id": "medical_history_input",
"type": "textAreaInput",
"label": "Relevant Medical History"
}

2. The Dropdown (selectInput)​

When you want the user to choose one option from a long list, a dropdown menu is the cleanest way to do it. You define the choices using an "options" array.

{
"id": "primary_language_select",
"type": "selectInput",
"label": "Primary Language",
"options": ["English", "Spanish", "French", "ASL", "Other"]
}

3. Visible choices (selectInput with buttons)​

For a short list of choices, use a selectInput with "flavor": "buttons" to show every option without opening a dropdown.

{
"id": "living_arrangement_select",
"type": "selectInput",
"flavor": "buttons",
"label": "Living Arrangement",
"options": ["Lives Alone", "Lives with Spouse", "Lives with Family", "Facility"]
}

(Don't forget to add "medical_history_input", "primary_language_select", and "living_arrangement_select" to your template's "children" array so they actually show up!)

See the full schema at this stage
// === Template nodes ======================================

{
"id": "my_first_evaluation_template",
"type": "template",
"label": "My Evaluation Template",
"appliesTo": "evaluation",
"children": [
"chief_complaint_input",
"medical_history_input",
"primary_language_select",
"living_arrangement_select",
"heck_yeah_text"
]
}

// === Text nodes ======================================

{
"id": "heck_yeah_text",
"type": "text",
"value": "Heck yeah!"
}

// === Input nodes ======================================

{
"id": "chief_complaint_input",
"type": "textInput",
"label": "Chief Complaint",
"placeholder": "Enter the primary reason for therapy...",
"tooltip": "Describe the primary reason for this evaluation.",
"isRequiredToSave": true
}

{
"id": "medical_history_input",
"type": "textAreaInput",
"label": "Relevant Medical History"
}

{
"id": "primary_language_select",
"type": "selectInput",
"label": "Primary Language",
"options": ["English", "Spanish", "French", "ASL", "Other"]
}

{
"id": "living_arrangement_select",
"type": "selectInput",
"flavor": "buttons",
"label": "Living Arrangement",
"options": ["Lives Alone", "Lives with Spouse", "Lives with Family", "Facility"]
}

The Problem with Repetition: Multi-Selects and Variables​

Suppose we want to document the patient's assistive devices.. Since a patient can have more than one device, we need a "multiSelectInput". This allows the user to click multiple options from a list. It could look something like this..

{
"id": "assistive_devices",
"type": "multiSelectInput",
"label": "Prior Assistive Devices",
"options": ["Cane", "Walker", "Wheelchair", "Crutches", "None"]
}

Then we decide we should actually capture the patient's current assistive devices and prior assistive devices. We we update our schema to support both nodes, like this:

{
"id": "prior_assistive_devices",
"type": "multiSelectInput",
"label": "Prior Assistive Devices",
"options": ["Cane", "Walker", "Wheelchair", "Crutches", "None"]
}

{
"id": "current_assistive_devices",
"type": "multiSelectInput",
"label": "Current Assistive Devices",
"options": ["Cane", "Walker", "Wheelchair", "Crutches", "None"]
}

Do you see the problem? We just copy-pasted the exact same array of options. It's wasteful. Worse, if we decide next week that we need to add "Rollator" to the list, we have to hunt down every single input in our schema that uses this list and update it manually. That is incredibly annoying and prone to errors.

The Solution: Reusable Variables​

Instead of defining the options directly inside the inputs, we can define a shared list once using a special node called an "options".

First, we create our variable node:

{
"id": "assistive_device_list",
"type": "options",
"items": ["Cane", "Walker", "Wheelchair", "Crutches", "Rollator", "None"]
}

Next, we update our multiSelectInput nodes. Instead of providing an array of strings, we just provide the ID of our new variable node as a string:

{
"id": "prior_assistive_devices",
"type": "multiSelectInput",
"label": "Prior Assistive Devices",
"options": "assistive_device_list" // Links to the variable node!
}

{
"id": "current_assistive_devices",
"type": "multiSelectInput",
"label": "Current Assistive Devices",
"options": "assistive_device_list" // Links to the exact same list!
}

Now, both inputs share the same underlying data list. Update "assistive_device_list" once, and every input referencing it updates automatically.

Add "prior_assistive_devices" and "current_assistive_devices" to My Evaluation Template's "children" array so both fields appear in the form.

Your fully updated schema should look something like this:

See the full schema at this stage
// === Templates ======================================

{
"id": "my_first_evaluation_template",
"type": "template",
"label": "My Evaluation Template",
"appliesTo": "evaluation",
"children": [
"chief_complaint_input",
"medical_history_input",
"primary_language_select",
"living_arrangement_select",
"prior_assistive_devices",
"current_assistive_devices",
"heck_yeah_text"
]
}

// === Text nodes ======================================

{
"id": "heck_yeah_text",
"type": "text",
"value": "Heck yeah!"
}

// === Input nodes ======================================

{
"id": "chief_complaint_input",
"type": "textInput",
"label": "Chief Complaint",
"placeholder": "Enter the primary reason for therapy...",
"tooltip": "Describe the primary reason for this evaluation.",
"isRequiredToSave": true
}

{
"id": "medical_history_input",
"type": "textAreaInput",
"label": "Relevant Medical History"
}

{
"id": "primary_language_select",
"type": "selectInput",
"label": "Primary Language",
"options": ["English", "Spanish", "French", "ASL", "Other"]
}

{
"id": "living_arrangement_select",
"type": "selectInput",
"flavor": "buttons",
"label": "Living Arrangement",
"options": ["Lives Alone", "Lives with Spouse", "Lives with Family", "Facility"]
}

{
"id": "prior_assistive_devices",
"type": "multiSelectInput",
"label": "Prior Assistive Devices",
"options": "assistive_device_list"
}

{
"id": "current_assistive_devices",
"type": "multiSelectInput",
"label": "Current Assistive Devices",
"options": "assistive_device_list"
}

// === Lists ======================================

{
"id": "assistive_device_list",
"type": "options",
"items": ["Cane", "Walker", "Wheelchair", "Crutches", "Rollator", "None"]
}

Multiple templates for the evaluation form​

Right now, our evaluation form just has one template option: My Evaluation Template. But what if your clinic handles different types of cases, like Pediatrics vs. Orthopedics? You wouldn't want to force your pediatric therapists to scroll through a bunch of joint replacement questions.

You can create as many templates as you want for a single form. All you have to do is create another "template" node and set "appliesTo": "evaluation".

{
"id": "pediatric_evaluation_template",
"type": "template",
"label": "Pediatric Evaluation",
"appliesTo": "evaluation", // This tells the system to show it in the evaluation form dropdown!
"children": [
"chief_complaint_input",
"pediatric_milestones_input"
]
}

{
"id": "pediatric_milestones_input",
"type": "textAreaInput",
"label": "Developmental Milestones",
"placeholder": "Describe relevant developmental milestones and current concerns."
}

The Magic of Node Reusability​

Notice something awesome in the code block above? We added "chief_complaint_input" to the pediatric template's children.

Nodes exist independently of templates. You don't have to recreate your inputs for every new template. You can define "chief_complaint_input" exactly once in your schema, and reference it across five different templates.

This guarantees consistency across your organization. If your clinical director decides the label should be changed from "Chief Complaint" to "Primary Reason for Referral", you update that single node, and the change automatically cascades to every template that uses it!

See the full schema at this stage
// === Templates ======================================

{
"id": "my_first_evaluation_template",
"type": "template",
"label": "My Evaluation Template",
"appliesTo": "evaluation",
"children": [
"chief_complaint_input",
"medical_history_input",
"primary_language_select",
"living_arrangement_select",
"prior_assistive_devices",
"current_assistive_devices",
"heck_yeah_text"
]
}

{
"id": "pediatric_evaluation_template",
"type": "template",
"label": "Pediatric Evaluation",
"appliesTo": "evaluation",
"children": [
"chief_complaint_input",
"pediatric_milestones_input"
]
}

// === Text nodes ======================================

{
"id": "heck_yeah_text",
"type": "text",
"value": "Heck yeah!"
}

// === Input nodes ======================================

{
"id": "chief_complaint_input",
"type": "textInput",
"label": "Chief Complaint",
"placeholder": "Enter the primary reason for therapy...",
"tooltip": "Describe the primary reason for this evaluation.",
"isRequiredToSave": true
}

{
"id": "medical_history_input",
"type": "textAreaInput",
"label": "Relevant Medical History"
}

{
"id": "primary_language_select",
"type": "selectInput",
"label": "Primary Language",
"options": ["English", "Spanish", "French", "ASL", "Other"]
}

{
"id": "living_arrangement_select",
"type": "selectInput",
"flavor": "buttons",
"label": "Living Arrangement",
"options": ["Lives Alone", "Lives with Spouse", "Lives with Family", "Facility"]
}

{
"id": "prior_assistive_devices",
"type": "multiSelectInput",
"label": "Prior Assistive Devices",
"options": "assistive_device_list"
}

{
"id": "current_assistive_devices",
"type": "multiSelectInput",
"label": "Current Assistive Devices",
"options": "assistive_device_list"
}

// === Lists ======================================

{
"id": "assistive_device_list",
"type": "options",
"items": ["Cane", "Walker", "Wheelchair", "Crutches", "Rollator", "None"]
}

{
"id": "pediatric_milestones_input",
"type": "textAreaInput",
"label": "Developmental Milestones",
"placeholder": "Describe relevant developmental milestones and current concerns."
}

Default templates​

A new evaluation has no default template until a matching template has a numeric priority. Add "priority": 1 to My Evaluation Template to select it automatically:

{
"id": "my_first_evaluation_template",
"type": "template",
"label": "My Evaluation Template",
"appliesTo": "evaluation",
"priority": 1,
"children": [
"chief_complaint_input",
"medical_history_input",
"primary_language_select",
"living_arrangement_select",
"prior_assistive_devices",
"current_assistive_devices",
"heck_yeah_text"
]
}

The matching template with the highest numeric priority is selected by default. If priorities tie, the template listed first in the schema wins. Templates without a numeric priority are not considered for default selection.

To make Pediatric Evaluation the default instead, give it a higher priority, such as 2. Clinicians can still choose another template in Custom data template.

See the full schema at this stage
// === Templates ======================================

{
"id": "my_first_evaluation_template",
"type": "template",
"label": "My Evaluation Template",
"appliesTo": "evaluation",
"priority": 1,
"children": [
"chief_complaint_input",
"medical_history_input",
"primary_language_select",
"living_arrangement_select",
"prior_assistive_devices",
"current_assistive_devices",
"heck_yeah_text"
]
}

{
"id": "pediatric_evaluation_template",
"type": "template",
"label": "Pediatric Evaluation",
"appliesTo": "evaluation",
"children": [
"chief_complaint_input",
"pediatric_milestones_input"
]
}

// === Text nodes ======================================

{
"id": "heck_yeah_text",
"type": "text",
"value": "Heck yeah!"
}

// === Input nodes ======================================

{
"id": "chief_complaint_input",
"type": "textInput",
"label": "Chief Complaint",
"placeholder": "Enter the primary reason for therapy...",
"tooltip": "Describe the primary reason for this evaluation.",
"isRequiredToSave": true
}

{
"id": "medical_history_input",
"type": "textAreaInput",
"label": "Relevant Medical History"
}

{
"id": "primary_language_select",
"type": "selectInput",
"label": "Primary Language",
"options": ["English", "Spanish", "French", "ASL", "Other"]
}

{
"id": "living_arrangement_select",
"type": "selectInput",
"flavor": "buttons",
"label": "Living Arrangement",
"options": ["Lives Alone", "Lives with Spouse", "Lives with Family", "Facility"]
}

{
"id": "prior_assistive_devices",
"type": "multiSelectInput",
"label": "Prior Assistive Devices",
"options": "assistive_device_list"
}

{
"id": "current_assistive_devices",
"type": "multiSelectInput",
"label": "Current Assistive Devices",
"options": "assistive_device_list"
}

// === Lists ======================================

{
"id": "assistive_device_list",
"type": "options",
"items": ["Cane", "Walker", "Wheelchair", "Crutches", "Rollator", "None"]
}

{
"id": "pediatric_milestones_input",
"type": "textAreaInput",
"label": "Developmental Milestones",
"placeholder": "Describe relevant developmental milestones and current concerns."
}

Treatment form template​

So far, our templates apply to evaluations. RehabAlpha also supports templates for treatments, progress reports, re-evaluations, and discharges.

To add a template to the treatment form, set "appliesTo": "treatment". This example collects the interventions provided and the patient's response.

Add this to your schema:

{
"id": "standard_treatment_template",
"type": "template",
"label": "Standard Treatment",
"appliesTo": "treatment",
"priority": 1,
"children": [
"interventions_input",
"treatment_response_input"
]
}

// Now, let's create the actual input nodes so they render correctly:
{
"id": "interventions_input",
"type": "textAreaInput",
"label": "Interventions",
"placeholder": "Describe the interventions provided during this treatment."
}

{
"id": "treatment_response_input",
"type": "textAreaInput",
"label": "Response to Treatment",
"placeholder": "Describe the patient's response to treatment."
}

When a clinician opens a treatment form, Standard Treatment appears in Custom data template. The evaluation templates appear only on evaluation forms.

Choose a treatment default​

The "priority": 1 in Standard Treatment selects it automatically for new treatments. Each document type has its own default selection, so My Evaluation Template remains the default for evaluations.

See the full schema at this stage
// === Templates ======================================

{
"id": "my_first_evaluation_template",
"type": "template",
"label": "My Evaluation Template",
"appliesTo": "evaluation",
"priority": 1,
"children": [
"chief_complaint_input",
"medical_history_input",
"primary_language_select",
"living_arrangement_select",
"prior_assistive_devices",
"current_assistive_devices",
"heck_yeah_text"
]
}

{
"id": "pediatric_evaluation_template",
"type": "template",
"label": "Pediatric Evaluation",
"appliesTo": "evaluation",
"children": [
"chief_complaint_input",
"pediatric_milestones_input"
]
}

// === Text nodes ======================================

{
"id": "heck_yeah_text",
"type": "text",
"value": "Heck yeah!"
}

// === Input nodes ======================================

{
"id": "chief_complaint_input",
"type": "textInput",
"label": "Chief Complaint",
"placeholder": "Enter the primary reason for therapy...",
"tooltip": "Describe the primary reason for this evaluation.",
"isRequiredToSave": true
}

{
"id": "medical_history_input",
"type": "textAreaInput",
"label": "Relevant Medical History"
}

{
"id": "primary_language_select",
"type": "selectInput",
"label": "Primary Language",
"options": ["English", "Spanish", "French", "ASL", "Other"]
}

{
"id": "living_arrangement_select",
"type": "selectInput",
"flavor": "buttons",
"label": "Living Arrangement",
"options": ["Lives Alone", "Lives with Spouse", "Lives with Family", "Facility"]
}

{
"id": "prior_assistive_devices",
"type": "multiSelectInput",
"label": "Prior Assistive Devices",
"options": "assistive_device_list"
}

{
"id": "current_assistive_devices",
"type": "multiSelectInput",
"label": "Current Assistive Devices",
"options": "assistive_device_list"
}

// === Lists ======================================

{
"id": "assistive_device_list",
"type": "options",
"items": ["Cane", "Walker", "Wheelchair", "Crutches", "Rollator", "None"]
}

// === Treatment template and inputs =======================

{
"id": "standard_treatment_template",
"type": "template",
"label": "Standard Treatment",
"appliesTo": "treatment",
"priority": 1,
"children": [
"interventions_input",
"treatment_response_input"
]
}

// Now, let's create the actual input nodes so they render correctly:
{
"id": "interventions_input",
"type": "textAreaInput",
"label": "Interventions",
"placeholder": "Describe the interventions provided during this treatment."
}

{
"id": "treatment_response_input",
"type": "textAreaInput",
"label": "Response to Treatment",
"placeholder": "Describe the patient's response to treatment."
}

{
"id": "pediatric_milestones_input",
"type": "textAreaInput",
"label": "Developmental Milestones",
"placeholder": "Describe relevant developmental milestones and current concerns."
}

As you add more and more questions to your templates, your forms are going to get long. A template with 30 inputs stacked one after another is visually overwhelming for clinicians.

To make forms easier to read and navigate, we can organize related inputs into sections using a "group" node.

A "group" node doesn't collect data on its own. It acts as a visual container that wraps its children together, providing a shared heading and description. Think of it like a folder for your fields.

Let's organize our subjective information (Chief Complaint and Medical History) into a group.

First, create the "group" node:

{
"id": "subjective_info_group",
"type": "group",
"label": "Subjective Information",
"description": "Information reported by the patient or caregiver regarding their current condition.",

// Notice that the group has its own children array!
"children": [
"chief_complaint_input",
"medical_history_input"
]
}

Now, instead of referencing those two inputs directly in our template, we just reference the group:

{
"id": "my_first_evaluation_template",
"type": "template",
"label": "My Evaluation Template",
"appliesTo": "evaluation",
"priority": 1,

// The template now points to the group, not the individual inputs
"children": [
"subjective_info_group",
"primary_language_select",
"living_arrangement_select",
"prior_assistive_devices",
"current_assistive_devices"
]
}

When you save this and check your form, you'll see a clean, distinct section titled Subjective Information, with the description underneath it, neatly boxing in your text inputs.

By strategically wrapping your fields in groups (e.g., "Demographics", "Subjective", "Objective", "Assessment"), your documentation becomes much more manageable!

See the full schema at this stage
// === Templates ======================================

{
"id": "my_first_evaluation_template",
"type": "template",
"label": "My Evaluation Template",
"appliesTo": "evaluation",
"priority": 1,
"children": [
"subjective_info_group",
"primary_language_select",
"living_arrangement_select",
"prior_assistive_devices",
"current_assistive_devices",
"heck_yeah_text"
]
}

{
"id": "pediatric_evaluation_template",
"type": "template",
"label": "Pediatric Evaluation",
"appliesTo": "evaluation",
"children": [
"chief_complaint_input",
"pediatric_milestones_input"
]
}

{
"id": "standard_treatment_template",
"type": "template",
"label": "Standard Treatment",
"appliesTo": "treatment",
"priority": 1,
"children": [
"interventions_input",
"treatment_response_input"
]
}

// === Group nodes =====================================

{
"id": "subjective_info_group",
"type": "group",
"label": "Subjective Information",
"description": "Information reported by the patient or caregiver regarding their current condition.",
"children": [
"chief_complaint_input",
"medical_history_input"
]
}

// === Text nodes ======================================

{
"id": "heck_yeah_text",
"type": "text",
"value": "Heck yeah!"
}

// === Input nodes ======================================

{
"id": "chief_complaint_input",
"type": "textInput",
"label": "Chief Complaint",
"placeholder": "Enter the primary reason for therapy...",
"tooltip": "Describe the primary reason for this evaluation.",
"isRequiredToSave": true
}

{
"id": "medical_history_input",
"type": "textAreaInput",
"label": "Relevant Medical History"
}

{
"id": "primary_language_select",
"type": "selectInput",
"label": "Primary Language",
"options": ["English", "Spanish", "French", "ASL", "Other"]
}

{
"id": "living_arrangement_select",
"type": "selectInput",
"flavor": "buttons",
"label": "Living Arrangement",
"options": ["Lives Alone", "Lives with Spouse", "Lives with Family", "Facility"]
}

{
"id": "prior_assistive_devices",
"type": "multiSelectInput",
"label": "Prior Assistive Devices",
"options": "assistive_device_list"
}

{
"id": "current_assistive_devices",
"type": "multiSelectInput",
"label": "Current Assistive Devices",
"options": "assistive_device_list"
}

{
"id": "interventions_input",
"type": "textAreaInput",
"label": "Interventions",
"placeholder": "Describe the interventions provided during this treatment."
}

{
"id": "treatment_response_input",
"type": "textAreaInput",
"label": "Response to Treatment",
"placeholder": "Describe the patient's response to treatment."
}

// === Lists ======================================

{
"id": "assistive_device_list",
"type": "options",
"items": ["Cane", "Walker", "Wheelchair", "Crutches", "Rollator", "None"]
}

{
"id": "pediatric_milestones_input",
"type": "textAreaInput",
"label": "Developmental Milestones",
"placeholder": "Describe relevant developmental milestones and current concerns."
}

Organizing nodes without adding a visible section​

Use a "fragment" node when you want to name and reuse a collection of children without adding another section to the form.

For example, a discipline-specific evaluation workflow might contain several visible groups:

{
"id": "occupational_therapy_evaluation_workflow",
"type": "fragment",
"children": [
"clinical_context_group",
"occupational_profile_group",
"assessment_and_plan_group"
]
}

You can then reference the fragment from a template or logic node just as you would reference a group:

{
"id": "occupational_therapy_evaluation_template",
"type": "template",
"label": "Evaluation",
"appliesTo": "evaluation",
"children": [
"occupational_therapy_evaluation_workflow"
]
}

The fragment itself does not render an element, heading, description, spacing, or right-side navigation entry. Its child groups render directly inside the template, so the navigation shows Evaluation β†’ Clinical Context instead of adding an unnecessary workflow level.

A fragment supports "showIf" when all of its children should appear or disappear together. It does not support "label", "description", or "colSpan"; use a group when you need those visual features.


Dynamically showing / hiding fields with conditional nodes​

Forms are best when they only ask for information that is actually relevant. For instance, you shouldn't ask a patient to rate their pain on a scale of 1 to 10 if they just told you they aren't experiencing any pain.

To solve this, RehabAlpha uses "conditional" nodes. A conditional node acts like a gatekeeper: it evaluates a rule you set, and if that rule is true, it displays its "children".

Example 1: A Dynamic Pain Assessment​

Let's build a pain assessment section where we only ask for a pain rating if the clinician checks a "Patient has pain" box.

First, let's create our two input fields: a checkbox and a number input.

{
"id": "has_pain_checkbox",
"type": "checkboxInput",
"label": "Patient is currently experiencing pain"
}

{
"id": "pain_scale_input",
"type": "numberInput",
"label": "Pain Scale (1-10)",
"min": 1,
"max": 10,
"isInteger": true
}

Now, we wrap the pain_scale_input inside a "conditional" node. We use the "when" property to define our rule:

{
"id": "pain_scale_conditional",
"type": "conditional",
"when": {
"field": "has_pain_checkbox", // We are checking the value of this field...
"equals": true // ...and it must equal true (checked) to pass!
},
"children": [
"pain_scale_input" // If true, show this input!
]
}

Finally, add both "has_pain_checkbox" and "pain_scale_conditional" to your template's children array. When the user checks the box, the pain scale will instantly appear!

See the full schema at this stage
// === Templates ======================================

{
"id": "my_first_evaluation_template",
"type": "template",
"label": "My Evaluation Template",
"appliesTo": "evaluation",
"priority": 1,
"children": [
"subjective_info_group",
"primary_language_select",
"living_arrangement_select",
"prior_assistive_devices",
"current_assistive_devices",
"has_pain_checkbox",
"pain_scale_conditional",
"heck_yeah_text"
]
}

{
"id": "pediatric_evaluation_template",
"type": "template",
"label": "Pediatric Evaluation",
"appliesTo": "evaluation",
"children": [
"chief_complaint_input",
"pediatric_milestones_input"
]
}

{
"id": "standard_treatment_template",
"type": "template",
"label": "Standard Treatment",
"appliesTo": "treatment",
"priority": 1,
"children": [
"interventions_input",
"treatment_response_input"
]
}

// === Group nodes =====================================

{
"id": "subjective_info_group",
"type": "group",
"label": "Subjective Information",
"description": "Information reported by the patient or caregiver regarding their current condition.",
"children": [
"chief_complaint_input",
"medical_history_input"
]
}

// === Conditional nodes ===============================

{
"id": "pain_scale_conditional",
"type": "conditional",
"when": {
"field": "has_pain_checkbox",
"equals": true
},
"children": [
"pain_scale_input"
]
}

// === Text nodes ======================================

{
"id": "heck_yeah_text",
"type": "text",
"value": "Heck yeah!"
}

// === Input nodes ======================================

{
"id": "chief_complaint_input",
"type": "textInput",
"label": "Chief Complaint",
"placeholder": "Enter the primary reason for therapy...",
"tooltip": "Describe the primary reason for this evaluation.",
"isRequiredToSave": true
}

{
"id": "medical_history_input",
"type": "textAreaInput",
"label": "Relevant Medical History"
}

{
"id": "primary_language_select",
"type": "selectInput",
"label": "Primary Language",
"options": ["English", "Spanish", "French", "ASL", "Other"]
}

{
"id": "living_arrangement_select",
"type": "selectInput",
"flavor": "buttons",
"label": "Living Arrangement",
"options": ["Lives Alone", "Lives with Spouse", "Lives with Family", "Facility"]
}

{
"id": "prior_assistive_devices",
"type": "multiSelectInput",
"label": "Prior Assistive Devices",
"options": "assistive_device_list"
}

{
"id": "current_assistive_devices",
"type": "multiSelectInput",
"label": "Current Assistive Devices",
"options": "assistive_device_list"
}

{
"id": "interventions_input",
"type": "textAreaInput",
"label": "Interventions",
"placeholder": "Describe the interventions provided during this treatment."
}

{
"id": "treatment_response_input",
"type": "textAreaInput",
"label": "Response to Treatment",
"placeholder": "Describe the patient's response to treatment."
}

{
"id": "has_pain_checkbox",
"type": "checkboxInput",
"label": "Patient is currently experiencing pain"
}

{
"id": "pain_scale_input",
"type": "numberInput",
"label": "Pain Scale (1-10)",
"min": 1,
"max": 10,
"isInteger": true
}

// === Lists ======================================

{
"id": "assistive_device_list",
"type": "options",
"items": ["Cane", "Walker", "Wheelchair", "Crutches", "Rollator", "None"]
}

{
"id": "pediatric_milestones_input",
"type": "textAreaInput",
"label": "Developmental Milestones",
"placeholder": "Describe relevant developmental milestones and current concerns."
}

Example 2: Using Special Context Variables​

Conditional nodes can evaluate more than just the inputs the user typed. RehabAlpha provides a set of Special Variables that give you context about the form being filled out, such as who is filling it out or where they are. Special variables always start with an asterisk (*).

Let's say you have a single Evaluation template used by all therapists, but you want to include a "Cognitive Level" dropdown that only appears if the form is linked to a Speech-Language Pathology (SLP) therapy case. We can check the special *disciplineId variable for this.

First, create the input:

{
"id": "cognitive_level_select",
"type": "selectInput",
"label": "Cognitive Level",
"options": ["Intact", "Mild Impairment", "Moderate Impairment", "Severe Impairment"]
}

Next, wrap it in a conditional node that checks if the clinician's discipline is "SLP":

{
"id": "slp_cognitive_conditional",
"type": "conditional",
"when": {
"field": "*disciplineId",
"equals": "SLP"
},
"children": [
"cognitive_level_select"
]
}

Add "slp_cognitive_conditional" to your template. Now, Physical Therapists and Occupational Therapists won't be bothered by this question, but it will automatically appear for your Speech Therapists!

See the full schema at this stage
// === Templates ======================================

{
"id": "my_first_evaluation_template",
"type": "template",
"label": "My Evaluation Template",
"appliesTo": "evaluation",
"priority": 1,
"children": [
"subjective_info_group",
"primary_language_select",
"living_arrangement_select",
"prior_assistive_devices",
"current_assistive_devices",
"has_pain_checkbox",
"pain_scale_conditional",
"slp_cognitive_conditional",
"heck_yeah_text"
]
}

{
"id": "pediatric_evaluation_template",
"type": "template",
"label": "Pediatric Evaluation",
"appliesTo": "evaluation",
"children": [
"chief_complaint_input",
"pediatric_milestones_input"
]
}

{
"id": "standard_treatment_template",
"type": "template",
"label": "Standard Treatment",
"appliesTo": "treatment",
"priority": 1,
"children": [
"interventions_input",
"treatment_response_input"
]
}

// === Group nodes =====================================

{
"id": "subjective_info_group",
"type": "group",
"label": "Subjective Information",
"description": "Information reported by the patient or caregiver regarding their current condition.",
"children": [
"chief_complaint_input",
"medical_history_input"
]
}

// === Conditional nodes ===============================

{
"id": "pain_scale_conditional",
"type": "conditional",
"when": {
"field": "has_pain_checkbox",
"equals": true
},
"children": [
"pain_scale_input"
]
}

{
"id": "slp_cognitive_conditional",
"type": "conditional",
"when": {
"field": "*disciplineId",
"equals": "SLP"
},
"children": [
"cognitive_level_select"
]
}

// === Text nodes ======================================

{
"id": "heck_yeah_text",
"type": "text",
"value": "Heck yeah!"
}

// === Input nodes ======================================

{
"id": "chief_complaint_input",
"type": "textInput",
"label": "Chief Complaint",
"placeholder": "Enter the primary reason for therapy...",
"tooltip": "Describe the primary reason for this evaluation.",
"isRequiredToSave": true
}

{
"id": "medical_history_input",
"type": "textAreaInput",
"label": "Relevant Medical History"
}

{
"id": "primary_language_select",
"type": "selectInput",
"label": "Primary Language",
"options": ["English", "Spanish", "French", "ASL", "Other"]
}

{
"id": "living_arrangement_select",
"type": "selectInput",
"flavor": "buttons",
"label": "Living Arrangement",
"options": ["Lives Alone", "Lives with Spouse", "Lives with Family", "Facility"]
}

{
"id": "prior_assistive_devices",
"type": "multiSelectInput",
"label": "Prior Assistive Devices",
"options": "assistive_device_list"
}

{
"id": "current_assistive_devices",
"type": "multiSelectInput",
"label": "Current Assistive Devices",
"options": "assistive_device_list"
}

{
"id": "interventions_input",
"type": "textAreaInput",
"label": "Interventions",
"placeholder": "Describe the interventions provided during this treatment."
}

{
"id": "treatment_response_input",
"type": "textAreaInput",
"label": "Response to Treatment",
"placeholder": "Describe the patient's response to treatment."
}

{
"id": "has_pain_checkbox",
"type": "checkboxInput",
"label": "Patient is currently experiencing pain"
}

{
"id": "pain_scale_input",
"type": "numberInput",
"label": "Pain Scale (1-10)",
"min": 1,
"max": 10,
"isInteger": true
}

{
"id": "cognitive_level_select",
"type": "selectInput",
"label": "Cognitive Level",
"options": ["Intact", "Mild Impairment", "Moderate Impairment", "Severe Impairment"]
}

// === Lists ======================================

{
"id": "assistive_device_list",
"type": "options",
"items": ["Cane", "Walker", "Wheelchair", "Crutches", "Rollator", "None"]
}

{
"id": "pediatric_milestones_input",
"type": "textAreaInput",
"label": "Developmental Milestones",
"placeholder": "Describe relevant developmental milestones and current concerns."
}