Core concepts
Dynamic Event Forms
Through the Admin portal, users can create all the forms they need and have them available on the mobile applications for the beneficiaries. Event Forms in Hikma Health are customizable, dynamic forms that allow healthcare providers to capture various types of patient data during clinical visits.
Table of Contents
- What are Event Forms?
- Dynamic Form System
- Input Types
- Form Properties
- Event Form Builder Guide
- Form Renderer
- Best Practices
- Technical Reference
- Troubleshooting
What are Event Forms?
The term "Event" is used to describe any and all interactions between a patient and a care provider.
Examples of Events include:
- Patient symptoms
- Patient treatment plans
- Dental examination
- Lab testing & investigations
- Physical examinations
- Triage assessments
- Specialist consultations
- Discharge summaries
Event Forms are structured data collection templates that define:
- What data to collect (field types and configurations)
- How to display it (input types and options)
- Validation rules (required fields, data types)
- Language support (multilingual forms)
Each form can be associated with patient events during visits and stores data in a structured format for analysis and reporting.
Dynamic Form System
How Forms are Dynamic
Event Forms are completely dynamic and configurable without code changes:
- Runtime Creation: Forms are created through a visual builder interface in the Admin portal, not hardcoded
- Field Flexibility: Add, remove, or reorder fields at any time
- Type Safety: Each field type has validation and structure
- Data Structure: Form definitions are stored as JSON in the database
- Instant Updates: Changes to forms are immediately available after syncing to mobile devices
Form Data Structure
{
"id": "uuid",
"name": "Physical Examination Form",
"description": "Standard physical exam checklist",
"language": "en",
"is_editable": true,
"is_snapshot_form": false,
"form_fields": [
{
"id": "field-id-123",
"fieldType": "free-text",
"inputType": "text",
"name": "Blood Pressure",
"description": "Systolic/Diastolic",
"required": true,
"length": "short"
}
// ... more fields
]
}
Input Types
Event Forms support 7 main field types, each with specific configurations:
1. Text Field (free-text)
Captures text or numeric input from users.
Configuration:
inputType:"text","number","email","password","tel"length:"short"or"long"(for textarea)units: Optional array of measurement units (e.g.,["kg", "lb"])
Use Cases:
- Patient weight with units (kg/lb)
- Height measurements (cm/in)
- Temperature readings (°C/°F)
- Free-text notes
- Phone numbers, emails
Example:
{
"id": "weight-field",
"fieldType": "free-text",
"inputType": "number",
"name": "Patient Weight",
"description": "Enter the patient's current weight",
"required": true,
"length": "short",
"units": ["kg", "lb"]
}
2. Binary/Checkbox Field (binary)
For yes/no or true/false questions.
Configuration:
inputType:"checkbox","radio","select"options: Array of options (typically Yes/No)
Use Cases:
- Symptom presence (Has fever? Yes/No)
- Medical history questions
- Consent checkboxes
Example:
{
"id": "fever-field",
"fieldType": "binary",
"inputType": "checkbox",
"name": "Patient has fever",
"description": "Check if patient reports fever",
"required": false,
"options": [
{ "label": "Yes", "value": "yes" },
{ "label": "No", "value": "no" }
]
}
3. Options Field (options)
Multiple choice questions with single or multiple selections.
Configuration:
inputType:"radio"(single),"checkbox"(multiple),"select"(dropdown)multi:truefor multiple selections,falsefor singleoptions: Array of choices
Use Cases:
- Symptom selection (multiple)
- Pain level (single choice)
- Treatment preferences
- Risk factors
Example:
{
"id": "symptoms-field",
"fieldType": "options",
"inputType": "checkbox",
"multi": true,
"name": "Current Symptoms",
"description": "Select all symptoms the patient is experiencing",
"required": true,
"options": [
{ "label": "Cough", "value": "cough" },
{ "label": "Fever", "value": "fever" },
{ "label": "Headache", "value": "headache" },
{ "label": "Fatigue", "value": "fatigue" },
{ "label": "Nausea", "value": "nausea" }
]
}
4. Date Field (date)
Captures date information.
Configuration:
inputType:"date"- Optional
min/maxdate constraints
Use Cases:
- Date of symptom onset
- Last vaccination date
- Surgery dates
- Follow-up appointment dates
Example:
{
"id": "onset-date",
"fieldType": "date",
"inputType": "date",
"name": "Symptom Onset Date",
"description": "When did symptoms first appear?",
"required": true
}
5. Medicine Field (medicine)
Complex field for prescribing medications with dosage, route, and schedule.
Configuration:
inputType:"input-group"options: Array of medicine names (autocomplete)fields: Object containing medication details
Medicine Subfields:
name: Medicine nameroute: Administration route (oral, IV, topical, etc.)form: Medicine form (tablet, syrup, injection, etc.)frequency: How often to take (e.g., "3 times daily")intervals: Time between dosesdose: Amount per dosedoseUnits: Unit of measurement (mg, mL, etc.)duration: How long to takedurationUnits: Time unit (days, weeks, months)
Available Routes: oral, sublingual, rectal, topical, inhalation, intravenous, intramuscular, intradermal, subcutaneous, nasal, ophthalmic, otic, vaginal, transdermal, other
Available Forms: tablet, syrup, ampule, suppository, cream, drops, bottle, spray, gel, lotion, inhaler, capsule, injection, patch, other
Dose Units: mg, g, mcg, mL, L, units
Duration Units: hours, days, weeks, months, years
Example:
{
"id": "medication-field",
"fieldType": "medicine",
"inputType": "input-group",
"name": "Prescribed Medication",
"description": "Enter medication details",
"required": true,
"options": ["Amoxicillin", "Paracetamol", "Ibuprofen"],
"fields": {
"name": "Medication Name",
"route": ["oral", "intravenous", "topical"],
"form": ["tablet", "syrup", "injection"],
"frequency": "Frequency",
"dose": "Dose",
"doseUnits": ["mg", "mL"],
"duration": "Duration",
"durationUnits": ["days", "weeks"]
}
}
Important Notes:
- Medicine inputs have mandatory fields and must be tested carefully
- Test the appearance after every change as inputs may interact with each other
- This is a custom input type with special handling
6. Diagnosis Field (diagnosis)
ICD-11 diagnosis picker with search functionality.
Configuration:
inputType:"select"options: Searchable ICD-11 diagnosis codes- Supports multiple diagnoses
Use Cases:
- Primary diagnosis
- Secondary diagnoses
- Differential diagnoses
Example:
{
"id": "diagnosis-field",
"fieldType": "diagnosis",
"inputType": "select",
"name": "ICD-11 Diagnosis",
"description": "Search and select diagnosis",
"required": true,
"options": []
}
Important Notes:
- This is a custom input type with special handling
- The diagnosis field name is reserved and cannot be used for other purposes
7. File Field (file)
Upload files, images, or documents.
Configuration:
inputType:"file"allowedMimeTypes: Restrict file types (["image/png", "image/jpeg", "application/pdf"])multiple: Allow multiple filesminItems: Minimum number of filesmaxItems: Maximum number of files
Use Cases:
- Medical images
- Lab results (PDF)
- Patient photos
- Consent forms
Example:
{
"id": "xray-upload",
"fieldType": "file",
"inputType": "file",
"name": "X-Ray Images",
"description": "Upload chest X-ray images",
"required": false,
"allowedMimeTypes": ["image/png", "image/jpeg"],
"multiple": true,
"minItems": 1,
"maxItems": 5
}
Form Properties
Core Properties
| Property | Type | Description |
|---|---|---|
id | string (UUID) | Unique identifier for the form |
name | string | Display name of the form |
description | string | Brief description of form purpose |
language | string | Language code (e.g., "en", "es", "ar") |
is_editable | boolean | Whether form responses can be edited after submission |
is_snapshot_form | boolean | If true, captures point-in-time data (non-editable) |
form_fields | array | Array of field definitions |
metadata | object | Additional custom metadata |
Field Properties
Every field has these base properties:
| Property | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique field identifier |
fieldType | string | Yes | Type of field (see Input Types) |
inputType | string | Yes | How the field is rendered |
name | string | Yes | Field label shown to user |
description | string | No | Help text for the field |
required | boolean | Yes | Whether field must be filled |
Reserved Field Names
The following field names are reserved and cannot be used:
diagnosismedicine
These names are reserved because they have special handling in the system.
Event Form Builder Guide
Accessing the Form Builder
- Navigate to Event Forms in the sidebar of the Admin portal
- Click "Register New Form" or "Edit" on an existing form
Creating a New Form
Step 1: Basic Information
Fill in the form metadata:
- Form Title: Give your form a descriptive name
- Form Language: Select the primary language
- Form Description: Explain when to use this form
- Is Editable: Check if responses can be modified later
- Is Snapshot: Check if this captures one-time data
Step 2: Adding Fields
Click the appropriate button to add a field type:
- Text - For text or numeric input
- Date - For date selection
- Select - For dropdown choices
- Radio - For single-choice options
- File - For file uploads
- Medicine - For prescriptions
- Diagnosis - For ICD-11 diagnoses
Step 3: Configuring Fields
For each field you add, configure:
- Field Name: The label users will see
- Description: Optional help text
- Required: Whether this field is mandatory
- Type-specific options:
- For Text: Choose short/long, add units if needed
- For Select/Radio: Add your options (one per line or comma-separated)
- For Medicine: Specify available medicines
- For File: Set allowed file types and limits
Step 4: Reordering Fields
Drag and drop fields to reorder them. The order in the builder is the order users will see.
Step 5: Preview
The right panel shows a live preview of your form as you build it.
Step 6: Save
Click "Save" to create/update the form. It becomes immediately available after mobile devices sync.
Editing Existing Forms
- Go to Event Forms → Forms List
- Click "Edit" on the form you want to modify
- Make your changes
- Click "Save"
⚠️ Important Notes:
- Editing a form affects all future uses
- Existing form responses are not modified
- As forms change and get updated, all data collected with the new forms will be slightly different from previous data
- When form inputs are edited and updated, keep in mind that users who try to edit old entries following the old schemas will have missing fields/entries
- Consider creating a new version for major changes
Form Settings
Is Editable
- ✅ Checked: Users can edit submitted responses
- ❌ Unchecked: Responses are locked after submission
Use Cases for Non-Editable:
- Legal documentation
- Consent forms
- Lab results
- Audit trails
Is Snapshot Form
- ✅ Checked: Captures data at a specific point in time and shows up under the patient profile for quick access to interesting patient histories
- ❌ Unchecked: General purpose form
Use Cases for Snapshot:
- Vital signs at admission
- Pre-operative assessment
- Triage data
- Baseline measurements
Language-Specific Forms
Important: Forms in a specific language only show up when the mobile app is set to that specific language. You can disable this behavior in the code by removing the language-specific query to show all forms regardless of language.
Best Practice: Create separate forms for each language and name them clearly:
- "Physical Exam (English)"
- "Physical Exam (Arabic)"
- "Physical Exam (Spanish)"
Deleting Forms
- Go to Event Forms → Forms List
- Click "Delete" on the form
- Confirm deletion
⚠️ Important:
- Deleted forms are soft-deleted (marked as deleted but not removed)
- Associated event data is preserved
- Forms cannot be recovered through the UI after deletion
Form Renderer
The mobile application has a set of screens and components that interpret the JSON form data and render out a functioning form capable of recording and storing the information.
How It Works
- Form Sync: Mobile apps sync form definitions from the database
- Dynamic Rendering: The app interprets the JSON structure and renders appropriate input components
- Data Collection: User input is collected and validated according to field rules
- Storage: Completed forms are stored as JSON in the
metadatafield on both client and server
Data Storage
- Forms are stored in the
event_formstable - Field definitions are stored as JSONB for flexibility
- Form responses are stored in the
eventstable withform_datafield - All form data is stored as JSON on both the client (SQLite) and the server
- Being a JSON field, managing this data is more complex. Learn more here: https://www.sqlite.org/json1.html
Input Customization on Mobile
- The input field components can be found inside the
componentsfolder - There are as many types of input components as there are field types in the TypeScript definitions
- Screen Size Considerations: Keep in mind the screen sizes of your users when customizing fields
- For users on smaller screens, it's not recommended to layout multiple fields in a row
- Prefer column layouts for smaller screens
- Test on actual devices (mobile/tablet) before deploying
Best Practices
Form Design
- Keep forms focused: One form = one purpose
- Use clear names: "Blood Pressure Reading" not "BP"
- Add descriptions: Help users understand what to enter
- Group related fields: Put related information together
- Minimize required fields: Only mark essential fields as required
Field Configuration
Text Fields:
- Use "short" for single-line input
- Use "long" for detailed notes
- Add units for measurements
- Use appropriate input types (number, email, tel)
Options Fields:
- Keep option lists concise (< 10 items when possible)
- Use radio buttons for 2-5 options
- Use select dropdowns for 5+ options
- Use checkboxes when multiple selections make sense
Medicine Fields:
- Pre-populate common medicines in options
- Include generic names
- Consider local medicine availability
- Test thoroughly as these have mandatory fields
Required Fields:
- Only mark fields as required if data is essential
- Consider workflow: Can form be partially filled and completed later?
Multilingual Support
- Create separate forms for each language
- Use consistent field structures across languages
- Name forms clearly: "Physical Exam (English)", "Physical Exam (Arabic)"
- Consider right-to-left languages in field design
Form Organization
Use logical ordering:
- Patient identification → History → Examination → Diagnosis → Treatment
Create form categories:
- Triage forms
- Specialist consultations
- Procedure documentation
- Discharge summaries
Version control:
- Include dates or version numbers in form names when creating updated versions
- Example: "Intake Form v2 (2024)"
Performance
- Limit form complexity: Very large forms (50+ fields) may impact performance
- Consider breaking large forms: Split into multiple focused forms
- Test with real data: Validate forms with actual clinical workflows
Data Quality
- Use validation: Leverage input types (number, email, date)
- Provide examples: Use descriptions to show expected formats
- Add units consistently: Always specify units for measurements
- Use standard codes: ICD-11 for diagnoses, standard drug names
Testing New Forms
Before deploying a new form:
- ✅ Fill out the form yourself with test data
- ✅ Check the preview panel matches your intent
- ✅ Test required field validation
- ✅ Verify dropdown options are complete
- ✅ Test on actual devices (mobile/tablet if applicable)
- ✅ Have a colleague review for clarity
Common Use Cases
Example 1: Social History Form
{
"name": "Social History",
"description": "Record patient social and lifestyle history",
"language": "en",
"is_editable": true,
"is_snapshot_form": false,
"form_fields": [
{
"id": "smoking-status",
"fieldType": "options",
"inputType": "radio",
"multi": false,
"name": "Smoking Status",
"required": true,
"options": [
{ "label": "Never", "value": "never" },
{ "label": "Former", "value": "former" },
{ "label": "Current", "value": "current" }
]
},
{
"id": "alcohol-use",
"fieldType": "options",
"inputType": "radio",
"multi": false,
"name": "Alcohol Use",
"required": true,
"options": [
{ "label": "None", "value": "none" },
{ "label": "Occasional", "value": "occasional" },
{ "label": "Regular", "value": "regular" }
]
},
{
"id": "occupation",
"fieldType": "options",
"inputType": "select",
"multi": false,
"name": "Occupation",
"required": false,
"options": [
{ "label": "Employed", "value": "employed" },
{ "label": "Unemployed", "value": "unemployed" },
{ "label": "Student", "value": "student" },
{ "label": "Retired", "value": "retired" }
]
},
{
"id": "exercise",
"fieldType": "binary",
"inputType": "checkbox",
"name": "Regular Exercise",
"required": false,
"options": [
{ "label": "Yes", "value": "yes" },
{ "label": "No", "value": "no" }
]
}
]
}
Example 2: Vital Signs Form (Snapshot)
This would include:
- Blood pressure (number with mmHg units)
- Heart rate (number with BPM units)
- Temperature (number with °C/°F units)
- Respiratory rate (number)
- Oxygen saturation (number with %)
- Weight (number with kg/lb units)
- Height (number with cm/in units)
Example 3: Consultation Form
This would include:
- Chief complaint (long text)
- History of present illness (long text)
- Examination findings (options + text)
- Diagnosis (diagnosis field)
- Treatment plan (medicine + text)
- Follow-up instructions (long text)
Example 4: Triage Form
This would include:
- Patient arrival time (date)
- Triage category (options: Red/Yellow/Green)
- Chief complaint (text)
- Vital signs (numbers with units)
- Alert status (binary)
- Priority notes (text)
Technical Reference
TypeScript Type Definitions
The form structure is defined by the following TypeScript types:
export type FieldType =
| 'binary'
| 'medicine'
| 'diagnosis'
| 'dosage'
| 'free-text'
| 'input-group'
| 'options'
| 'date'
| 'custom'
export type HHFieldBase = {
id: string
name: string
description: string
required: boolean
}
export type FieldOption = {
label: string
value: string
}
export type BinaryField = HHFieldBase & {
fieldType: 'binary'
inputType: 'checkbox' | 'radio' | 'select'
options: FieldOption[]
}
export type OptionsField = HHFieldBase & {
fieldType: 'options'
inputType: 'checkbox' | 'radio' | 'select'
options: FieldOption[]
}
export type DiagnosisField = HHFieldBase & {
fieldType: 'diagnosis'
inputType: 'select'
options: FieldOption[]
}
export type TextField = HHFieldBase &
(
| {
fieldType: 'free-text'
inputType: 'text' | 'number' | 'email' | 'password' | 'tel'
length: 'short'
units?: DoseUnit[] | DurationUnit[]
}
| {
fieldType: 'free-text'
inputType: 'textarea'
length: 'long'
units?: DoseUnit[] | DurationUnit[]
}
)
export type MedicineField = HHFieldBase & {
fieldType: 'medicine'
inputType: 'input-group'
fields: {
name: TextField
route: MedicineRoute
form: MedicineForm
frequency: TextField
intervals: TextField
dose: TextField
doseUnits: DoseUnit
duration: TextField
durationUnits: DurationUnit
}
}
type MedicationEntry = {
name: string
route: MedicineRoute
form: MedicineForm
frequency: number
intervals: number
dose: number
doseUnits: DoseUnit
duration: number
durationUnits: DurationUnit
}
export type DateField = HHFieldBase & {
fieldType: 'date'
inputType: 'date'
min?: Date
max?: Date
}
export type HHField =
| BinaryField
| TextField
| MedicineField
| DiagnosisField
| DateField
| OptionsField
Field Validation
All fields are validated using Effect schemas for type safety. Invalid field configurations will be caught before saving.
Measurement Units Available
Length: cm, m, in, ft
Weight: kg, lb
Pressure: mmHg, cmH2O, mmH2O
Temperature: °C, °F
Rate: BPM, P
Concentration: mmol/L, mg/dL, %
Dose: mg, g, mcg, mL, L, units
Troubleshooting
Issue: Form won't save
Possible causes:
- Duplicate field names
- Using reserved field names (diagnosis, medicine)
- Missing required field properties
- Invalid field configuration
Solution:
- Check browser console for validation errors
- Ensure all required field properties are set
- Verify field names are unique
- Check that field configurations match the expected structure
Issue: Field not showing in preview
Possible causes:
- Field type not supported in preview
- Field configuration incomplete
- Missing required properties
Solution:
- Ensure all required field properties are set
- Check that
fieldTypeandinputTypeare valid - Verify the field structure matches the TypeScript definitions
Issue: Options not appearing in dropdown
Possible causes:
- Options array is empty
- Options not properly formatted
- Invalid option structure
Solution:
- Check that options follow format:
{ label: "Display", value: "value" } - Ensure options array is not empty
- Verify JSON structure is valid
Issue: Form not appearing on mobile app
Possible causes:
- Language mismatch between form and app
- Form not synced to mobile device
- Form marked as deleted
Solution:
- Verify the form language matches the mobile app language setting
- Ensure mobile device has synced with the server
- Check that form is not soft-deleted in the database
Issue: Cannot edit old form entries
Possible causes:
- Form schema has changed since entry was created
- Form marked as non-editable
- Form is a snapshot form
Solution:
- Check if
is_editableis set to false - Verify form hasn't been significantly modified since entry creation
- Note that snapshot forms may have different edit permissions
Support
For additional help or to report issues with the Event Form system:
- Check the application logs for error details
- Consult with your system administrator
- Review existing forms for examples
- Contact the Hikma Health support team
- Refer to the SQLite JSON documentation: https://www.sqlite.org/json1.html