Writing Your Own Schema
This guide assumes you've already set up a therapy company in RehabAlpha. Furthermore, we assume you're signed in to that company and have admin privileges.
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_case_template",
"type": "template",
"label": "My Case Template",
"appliesTo": "case",
"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, create a patient, and then create a new case for that patient. Inside the "Create Case" form, you should see a select field where you get to pick a template. Click it and choose the only available option, "My Case Template".
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:
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!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": "case"so RehabAlpha knows this template belongs in the Case 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_case_template",
"type": "template",
"label": "My Case Template",
"appliesTo": "case",
"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 Case form.
* For now, it'll have one child node - a text node, that displays "Heck yeah!"
*/
{
"id": "my_first_case_template", // This is the node's unique identifier
"type": "template", // This is a template node
"label": "My Case Template", // This label will appear in the template drop down list
"appliesTo": "case", // This template will appear as an option in the Case 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_case_template",
"type": "template",
"label": "My Case Template",
"appliesTo": "case",
// 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": "For internal use only - won't be submitted to Medicare",
"isRequiredToSave": true
}
Save the schema. Go back to your patient and create a new case. Then select My Case Template in the template drop down. You should now see a fully functioning text box!
Each time you change your organization's schema, it creates a new schema version. (The old version still exists.) To see the new version in action, you need to create a brand new therapy case. Previously saved cases will be linked to the old schema version.
(This isn't entirely true, but the rules & details here get tricky... Reach out to us if you really need to know how this works.)
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": "For internal use only - won't be submitted to Medicare", // 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 totrueenforces 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_case_template",
"type": "template",
"label": "My Case Template",
"appliesTo": "case",
"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": "For internal use only - won't be submitted to Medicare",
"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_case_template",
"type": "template",
"label": "My Case Template",
"appliesTo": "case",
// 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_case_template",
"type": "template",
"label": "My Case Template",
"appliesTo": "case",
"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": "For internal use only - won't be submitted to Medicare",
"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. The Radio Buttons (radioInput)β
When you have a short list of choices and want the user to see all the options immediately without clicking a dropdown menu, use a radioInput.
{
"id": "living_arrangement_radio",
"type": "radioInput",
"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_radio" to your template's "children" array so they actually show up!)
See the full schema at this stage
// === Template nodes ======================================
{
"id": "my_first_case_template",
"type": "template",
"label": "My Case Template",
"appliesTo": "case",
"children": [
"chief_complaint_input",
"medical_history_input",
"primary_language_select",
"living_arrangement_radio",
"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": "For internal use only - won't be submitted to Medicare",
"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_radio",
"type": "radioInput",
"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.
Your fully updated schema should look something like this:
See the full schema at this stage
// === Templates ======================================
{
"id": "my_first_case_template",
"type": "template",
"label": "My Case Template",
"appliesTo": "case",
"children": [
"chief_complaint_input",
"medical_history_input",
"primary_language_select",
"living_arrangement_radio",
"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": "For internal use only - won't be submitted to Medicare",
"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_radio",
"type": "radioInput",
"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 Case Formβ
Right now, our case form just has one template option: My Case 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": "case".
{
"id": "pediatric_case_template",
"type": "template",
"label": "Pediatric Case",
"appliesTo": "case", // This tells the system to show it in the Case form dropdown!
"children": [
"chief_complaint_input",
"pediatric_milestones_input"
]
}
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_case_template",
"type": "template",
"label": "My Case Template",
"appliesTo": "case",
"children": [
"chief_complaint_input",
"medical_history_input",
"primary_language_select",
"living_arrangement_radio",
"heck_yeah_text"
]
}
{
"id": "pediatric_case_template",
"type": "template",
"label": "Pediatric Case",
"appliesTo": "case",
"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": "For internal use only - won't be submitted to Medicare",
"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_radio",
"type": "radioInput",
"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"]
}
Default templatesβ
Right now, when we create a new therapy case the template drop down box is empty by default. Users have to click the drop down and choose a template. In practice, we'll probably want to provide them with a default option to save them a click. We can achieve this via a templateDefaults node.
A templateDefaults node acts like a dictionary that tells the system which template ID should be automatically selected for a specific document type.
Let's update our schema to include a templateDefaults node. Add the following to your schema array:
{
"id": "my_org_template_defaults",
"type": "templateDefaults",
"defaults": {
// The key is the document type, the value is the template ID
"case": "my_first_case_template"
}
}
By adding this single node, the system knows to look at the "defaults" object. Whenever a user opens a "case" form, it will automatically select the template with the ID "my_first_case_template". If you ever want to make your Pediatric Case the default instead, you just change that one string to "pediatric_case_template".
Now, when users create a new therapy case, the My Case Template template is selected by default!
See the full schema at this stage
// === Templates ======================================
{
"id": "my_first_case_template",
"type": "template",
"label": "My Case Template",
"appliesTo": "case",
"children": [
"chief_complaint_input",
"medical_history_input",
"primary_language_select",
"living_arrangement_radio",
"heck_yeah_text"
]
}
{
"id": "pediatric_case_template",
"type": "template",
"label": "Pediatric Case",
"appliesTo": "case",
"children": [
"chief_complaint_input",
"pediatric_milestones_input"
]
}
// Template defaults
{
"id": "my_org_template_defaults",
"type": "templateDefaults",
"defaults": {
"case": "my_first_case_template"
}
}
// === 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": "For internal use only - won't be submitted to Medicare",
"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_radio",
"type": "radioInput",
"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"]
}
Evaluation form templateβ
So far, we've only built templates for the "case" form (the form used when creating a brand new therapy case). But RehabAlpha has several different form types: evaluations, daily treatment notes, progress reports, discharges, etc.
To create a template that shows up in the Evaluation form, we do the exact same thing we did for the case template, but we change the "appliesTo" property to "evaluation".
Add this to your schema:
{
"id": "standard_evaluation_template",
"type": "template",
"label": "Standard Evaluation",
"appliesTo": "evaluation", // Notice the change here!
"children": [
"prior_level_of_function_input",
"clinical_assessment_input"
]
}
// Now, let's create the actual input nodes so they render correctly:
{
"id": "prior_level_of_function_input",
"type": "textAreaInput",
"label": "Prior Level of Function",
"placeholder": "Describe the patient's abilities prior to the onset of this condition."
}
{
"id": "clinical_assessment_input",
"type": "textAreaInput",
"label": "Clinical Assessment",
"placeholder": "Synthesize the evaluation findings and your clinical impression."
}
When a user opens an Evaluation form, they will now see Standard Evaluation in the template dropdown. They will not see "My Case Template", because that template is explicitly restricted to "case" forms.
Updating your defaultsβ
We can also update our templateDefaults node so this new evaluation template is selected automatically whenever a clinician starts an eval:
{
"id": "my_org_template_defaults",
"type": "templateDefaults",
"defaults": {
"case": "my_first_case_template",
"evaluation": "standard_evaluation_template" // Added this line!
}
}
See the full schema at this stage
// === Templates ======================================
{
"id": "my_first_case_template",
"type": "template",
"label": "My Case Template",
"appliesTo": "case",
"children": [
"chief_complaint_input",
"medical_history_input",
"primary_language_select",
"living_arrangement_radio",
"heck_yeah_text"
]
}
{
"id": "pediatric_case_template",
"type": "template",
"label": "Pediatric Case",
"appliesTo": "case",
"children": [
"chief_complaint_input",
"pediatric_milestones_input"
]
}
{
"id": "standard_evaluation_template",
"type": "template",
"label": "Standard Evaluation",
"appliesTo": "evaluation",
"children": [
"prior_level_of_function_input",
"clinical_assessment_input"
]
}
// Template defaults
{
"id": "my_org_template_defaults",
"type": "templateDefaults",
"defaults": {
"case": "my_first_case_template",
"evaluation": "standard_evaluation_template"
}
}
// === 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": "For internal use only - won't be submitted to Medicare",
"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_radio",
"type": "radioInput",
"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": "prior_level_of_function_input",
"type": "textAreaInput",
"label": "Prior Level of Function",
"placeholder": "Describe the patient's abilities prior to the onset of this condition."
}
{
"id": "clinical_assessment_input",
"type": "textAreaInput",
"label": "Clinical Assessment",
"placeholder": "Synthesize the evaluation findings and your clinical impression."
}
// === Lists ======================================
{
"id": "assistive_device_list",
"type": "options",
"items": ["Cane", "Walker", "Wheelchair", "Crutches", "Rollator", "None"]
}
Grouping related fields with group nodesβ
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_case_template",
"type": "template",
"label": "My Case Template",
"appliesTo": "case",
// The template now points to the group, not the individual inputs
"children": [
"subjective_info_group",
"primary_language_select",
"living_arrangement_radio"
]
}
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_case_template",
"type": "template",
"label": "My Case Template",
"appliesTo": "case",
"children": [
"subjective_info_group",
"primary_language_select",
"living_arrangement_radio",
"heck_yeah_text"
]
}
{
"id": "pediatric_case_template",
"type": "template",
"label": "Pediatric Case",
"appliesTo": "case",
"children": [
"chief_complaint_input",
"pediatric_milestones_input"
]
}
{
"id": "standard_evaluation_template",
"type": "template",
"label": "Standard Evaluation",
"appliesTo": "evaluation",
"children": [
"prior_level_of_function_input",
"clinical_assessment_input"
]
}
// Template defaults
{
"id": "my_org_template_defaults",
"type": "templateDefaults",
"defaults": {
"case": "my_first_case_template",
"evaluation": "standard_evaluation_template"
}
}
// === 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": "For internal use only - won't be submitted to Medicare",
"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_radio",
"type": "radioInput",
"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": "prior_level_of_function_input",
"type": "textAreaInput",
"label": "Prior Level of Function",
"placeholder": "Describe the patient's abilities prior to the onset of this condition."
}
{
"id": "clinical_assessment_input",
"type": "textAreaInput",
"label": "Clinical Assessment",
"placeholder": "Synthesize the evaluation findings and your clinical impression."
}
// === Lists ======================================
{
"id": "assistive_device_list",
"type": "options",
"items": ["Cane", "Walker", "Wheelchair", "Crutches", "Rollator", "None"]
}
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
}
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_case_template",
"type": "template",
"label": "My Case Template",
"appliesTo": "case",
"children": [
"subjective_info_group",
"primary_language_select",
"living_arrangement_radio",
"has_pain_checkbox",
"pain_scale_conditional",
"heck_yeah_text"
]
}
{
"id": "pediatric_case_template",
"type": "template",
"label": "Pediatric Case",
"appliesTo": "case",
"children": [
"chief_complaint_input",
"pediatric_milestones_input"
]
}
{
"id": "standard_evaluation_template",
"type": "template",
"label": "Standard Evaluation",
"appliesTo": "evaluation",
"children": [
"prior_level_of_function_input",
"clinical_assessment_input"
]
}
// Template defaults
{
"id": "my_org_template_defaults",
"type": "templateDefaults",
"defaults": {
"case": "my_first_case_template",
"evaluation": "standard_evaluation_template"
}
}
// === 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": "For internal use only - won't be submitted to Medicare",
"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_radio",
"type": "radioInput",
"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": "prior_level_of_function_input",
"type": "textAreaInput",
"label": "Prior Level of Function",
"placeholder": "Describe the patient's abilities prior to the onset of this condition."
}
{
"id": "clinical_assessment_input",
"type": "textAreaInput",
"label": "Clinical Assessment",
"placeholder": "Synthesize the evaluation findings and your clinical impression."
}
{
"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
}
// === Lists ======================================
{
"id": "assistive_device_list",
"type": "options",
"items": ["Cane", "Walker", "Wheelchair", "Crutches", "Rollator", "None"]
}
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_case_template",
"type": "template",
"label": "My Case Template",
"appliesTo": "case",
"children": [
"subjective_info_group",
"primary_language_select",
"living_arrangement_radio",
"has_pain_checkbox",
"pain_scale_conditional",
"slp_cognitive_conditional",
"heck_yeah_text"
]
}
{
"id": "pediatric_case_template",
"type": "template",
"label": "Pediatric Case",
"appliesTo": "case",
"children": [
"chief_complaint_input",
"pediatric_milestones_input"
]
}
{
"id": "standard_evaluation_template",
"type": "template",
"label": "Standard Evaluation",
"appliesTo": "evaluation",
"children": [
"prior_level_of_function_input",
"clinical_assessment_input"
]
}
// Template defaults
{
"id": "my_org_template_defaults",
"type": "templateDefaults",
"defaults": {
"case": "my_first_case_template",
"evaluation": "standard_evaluation_template"
}
}
// === 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": "For internal use only - won't be submitted to Medicare",
"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_radio",
"type": "radioInput",
"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": "prior_level_of_function_input",
"type": "textAreaInput",
"label": "Prior Level of Function",
"placeholder": "Describe the patient's abilities prior to the onset of this condition."
}
{
"id": "clinical_assessment_input",
"type": "textAreaInput",
"label": "Clinical Assessment",
"placeholder": "Synthesize the evaluation findings and your clinical impression."
}
{
"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
}
{
"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"]
}