npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@robertotaylor0/mediform-client-sdk

v1.1.2

Published

Client SDK for integrating MediForm forms into EHR applications

Readme

@robertotaylor0/mediform-client-sdk

Official JavaScript/TypeScript SDK for integrating MediForm forms into EHR applications.

Features

  • 🚀 Easy Integration - Simple API for fetching and rendering forms
  • 🔒 Secure - API key authentication with rate limiting
  • Fast - Built-in caching and optimized API calls
  • 🎨 Customizable - Theme support and custom components
  • Validation - Comprehensive client-side validation
  • 🤖 AI Auto-Population - Extract values from images and text using AI
  • 📱 Responsive - Mobile-friendly form rendering
  • Accessible - WCAG 2.1 AA compliant
  • 🔧 TypeScript - Full type definitions included

Installation

npm install @robertotaylor0/mediform-client-sdk
# or
yarn add @robertotaylor0/mediform-client-sdk
# or
pnpm add @robertotaylor0/mediform-client-sdk

Quick Start

1. Initialize the Client

import { MediFormClient } from '@robertotaylor0/mediform-client-sdk';

const client = new MediFormClient({
  apiKey: 'mk_your_api_key_here',
  baseUrl: 'https://your-mediform-instance.com',
  cache: true, // Enable caching (default: true)
  defaultEnvironment: 'prod', // Optional, defaults to 'prod'
});

New in v2.0: The SDK now supports environment-based form publishing. See the Environments section below.

2. Fetch a Form

// Get a specific form
const form = await client.getForm('form-id');

// List available forms
const { items, pagination } = await client.listForms({
  category: 'intake',
  page: 1,
  limit: 20,
});

// Get a specific version
const formV2 = await client.getFormVersion('template-id', 2);

3. Render the Form (React)

import { FormRenderer } from '@robertotaylor0/mediform-client-sdk';
import '@robertotaylor0/mediform-client-sdk/dist/index.css';

function PatientForm() {
  const [form, setForm] = useState(null);

  useEffect(() => {
    client.getForm('patient-intake')
      .then(setForm)
      .catch(console.error);
  }, []);

  const handleSubmit = async (data) => {
    console.log('Form data:', data);
    // Process form data in your EHR
    await saveToEHR(data);
  };

  if (!form) return <div>Loading...</div>;

  return (
    <FormRenderer
      formDefinition={form.formDefinition}
      customCss={form.customCss}
      onSubmit={handleSubmit}
      onChange={(data) => console.log('Changed:', data)}
      theme={{
        colors: {
          primary: '#007bff',
          error: '#dc3545',
        },
      }}
    />
  );
}

Environments

The MediForm platform supports environment-based publishing, allowing forms to be published to different environments (Production, Development, Test, etc.) with independent versioning.

Configuration

Set a default environment when initializing the client:

const client = new MediFormClient({
  apiKey: 'mk_your_api_key',
  baseUrl: 'https://your-instance.com',
  defaultEnvironment: 'prod', // Defaults to 'prod' if not specified
});

Fetching from Specific Environments

// List forms from default environment (prod)
const forms = await client.listForms();

// List forms from specific environment
const devForms = await client.listForms({ environment: 'dev' });
const testForms = await client.listForms({ environment: 'test' });

// Get form by template ID + environment (returns latest version in that environment)
const prodForm = await client.getForm('template-id', 'prod');
const devForm = await client.getForm('template-id', 'dev');

// The form object includes environment information
console.log(prodForm.environment); // 'prod'
console.log(prodForm.version); // Version number in that environment

Listing Available Environments

const { environments } = await client.listEnvironments();

environments.forEach(env => {
  console.log(`${env.name} (${env.slug})`);
  console.log(`  Default: ${env.isDefault}`);
  if (env.description) {
    console.log(`  Description: ${env.description}`);
  }
});

// Example output:
// Production (prod)
//   Default: true
//   Description: Production environment for live forms
// Development (dev)
//   Default: false
//   Description: Development environment for testing
// Test (test)
//   Default: false
//   Description: QA and validation environment

Environment Use Cases

1. Development/Production Separation:

// Fetch development forms for testing
const devForm = await client.getForm('intake-form', 'dev');

// Fetch production forms for live use
const prodForm = await client.getForm('intake-form', 'prod');

2. Dynamic Environment Selection:

const environment = process.env.NODE_ENV === 'production' ? 'prod' : 'dev';
const form = await client.getForm('intake-form', environment);

3. Multi-Environment Support:

// Application supports multiple customer environments
const clientEnv = customerConfig.environment; // 'client-a-prod', 'client-b-prod', etc.
const forms = await client.listForms({ environment: clientEnv });

Environment-Aware Caching

The SDK automatically includes environment in cache keys, ensuring forms from different environments don't collide in the cache.

// These are cached separately:
await client.getForm('form-1', 'prod'); // Cache key: 'form:form-1:prod'
await client.getForm('form-1', 'dev');  // Cache key: 'form:form-1:dev'

API Reference

MediFormClient

Constructor

new MediFormClient(config: MediFormClientConfig)

Config Options:

  • apiKey (required): Your MediForm API key
  • baseUrl (required): URL of your MediForm instance
  • cache (optional): Enable response caching (default: true)
  • cacheTimeout (optional): Cache timeout in milliseconds (default: 300000 = 5 min)

Methods

listForms(filter?: FormListFilter): Promise<PaginatedResponse<FormListItem>>

List all available forms with optional filtering.

const result = await client.listForms({
  category: 'intake',
  tags: ['diabetes', 'cardiology'],
  search: 'patient',
  page: 1,
  limit: 20,
});

console.log(result.items); // Array of forms
console.log(result.pagination); // Pagination info

// ⚠️ IMPORTANT: Access form properties via metadata object
result.items.forEach(form => {
  // ✅ Correct way - metadata is nested:
  console.log(form.metadata.name);        // Form name
  console.log(form.metadata.description); // Form description
  console.log(form.metadata.category);    // Form category
  console.log(form.metadata.tags);        // Form tags array
  
  // These are at root level:
  console.log(form.id);                   // Form ID
  console.log(form.version);              // Version number
});

FormListItem Structure:

interface FormListItem {
  id: string;              // Published form ID
  templateId: string;      // Template ID
  version: number;         // Version number
  metadata: {              // ⚠️ Metadata is NESTED
    name: string;          // Form name
    description?: string;  // Form description
    tags?: string[];       // Form tags
    category?: string;     // Form category
  };
  publishedAt: string;     // ISO timestamp
}
getForm(formId: string): Promise<FormDefinition>

Fetch a complete form definition by ID.

const form = await client.getForm('published-form-id');

// Full structure:
console.log(form.id);                    // Published form ID
console.log(form.templateId);            // Template ID  
console.log(form.version);               // Version number
console.log(form.formDefinition);        // FormElement (the actual form)
console.log(form.customCss);             // CSS string
console.log(form.publishedAt);           // ISO timestamp

// ⚠️ Metadata is nested:
console.log(form.metadata.name);         // ✅ Form name
console.log(form.metadata.description);  // ✅ Description
console.log(form.metadata.category);     // ✅ Category
console.log(form.metadata.tags);         // ✅ Tags array

// ❌ These don't exist at root:
// console.log(form.name);               // undefined!
// console.log(form.description);        // undefined!
getFormVersion(formId: string, version: number): Promise<FormDefinition>

Fetch a specific version of a form.

const formV1 = await client.getFormVersion('template-id', 1);
const formV2 = await client.getFormVersion('template-id', 2);

Working with Form List Items

When displaying forms from listForms(), remember that form details are nested in the metadata object:

import { MediFormClient } from '@robertotaylor0/mediform-client-sdk';
import { useState, useEffect } from 'react';

function FormList() {
  const [forms, setForms] = useState([]);

  useEffect(() => {
    client.listForms().then(response => {
      setForms(response.items);
    });
  }, []);

  return (
    <div>
      {forms.map(form => (
        <div key={form.id}>
          {/* ✅ CORRECT: Access via metadata object */}
          <h2>{form.metadata.name}</h2>
          <p>{form.metadata.description}</p>
          <span>Category: {form.metadata.category}</span>
          
          {/* ❌ INCORRECT: These will be undefined */}
          {/* <h2>{form.name}</h2> */}
          {/* <p>{form.description}</p> */}
          
          {/* ✅ CORRECT: Version is at root level */}
          <span>Version: {form.version}</span>
          
          {form.metadata.tags && (
            <div>
              {form.metadata.tags.map(tag => (
                <span key={tag} className="tag">{tag}</span>
              ))}
            </div>
          )}
        </div>
      ))}
    </div>
  );
}
submitForm(formId: string, data: FormData): Promise<SubmissionResult>

Submit form data (if submission endpoint is enabled).

const result = await client.submitForm('form-id', {
  patientName: 'John Doe',
  age: 45,
  symptoms: ['fever', 'cough'],
});

console.log(result.id); // Submission ID
clearCache(): void

Clear all cached responses.

client.clearCache();
extractFormValues(formId: string, input: ExtractionInput): Promise<ExtractionResult>

Extract form values from an image or text using AI (requires AI extraction to be enabled).

// Extract from an image (data URI)
const result = await client.extractFormValues('form-id', {
  completedFormImageUri: 'data:image/png;base64,iVBORw0KG...',
});

// Extract from text
const result = await client.extractFormValues('form-id', {
  completedFormText: 'Patient name: John Doe, Age: 45, Symptoms: fever, cough',
});

// Process extracted values
Object.entries(result.extractions).forEach(([fieldId, extraction]) => {
  console.log(`${fieldId}:`, extraction.value);
  console.log(`Confidence: ${extraction.confidence * 100}%`);
  if (extraction.originalText) {
    console.log(`Original text: ${extraction.originalText}`);
  }
});
checkHealth(): Promise<HealthStatus>

Check API health status.

const health = await client.checkHealth();
console.log(health.status); // 'healthy'

FormRenderer

React component for rendering forms.

Props

interface FormRendererProps {
  formDefinition: FormElement;
  onSubmit?: (data: FormData) => void | Promise<void>;
  onChange?: (data: Partial<FormData>) => void;
  initialValues?: Partial<FormData>;
  theme?: ThemeConfig;
  customComponents?: ComponentMap;
  customCss?: string;
  showValidation?: boolean;
  disabled?: boolean;
}

Props Details:

  • formDefinition (required): The form structure from API
  • onSubmit (optional): Called when form is submitted with valid data
  • onChange (optional): Called whenever form data changes
  • initialValues (optional): Pre-populate form fields
  • theme (optional): Custom theme configuration
  • customComponents (optional): Override default field components
  • customCss (optional): Additional CSS styles
  • showValidation (optional): Show validation errors (default: true)
  • disabled (optional): Disable all form fields

Example with All Props

<FormRenderer
  formDefinition={form.formDefinition}
  onSubmit={handleSubmit}
  onChange={(data) => console.log('Data:', data)}
  initialValues={{ patientName: 'John Doe', age: 45 }}
  theme={{
    colors: {
      primary: '#007bff',
      secondary: '#6c757d',
      error: '#dc3545',
      success: '#28a745',
      background: '#ffffff',
      border: '#dee2e6',
    },
    fonts: {
      family: 'Arial, sans-serif',
      size: '16px',
    },
    spacing: {
      field: '1rem',
      section: '2rem',
    },
  }}
  customComponents={{
    text: MyCustomTextField,
    number: MyCustomNumberField,
  }}
  customCss=".my-form { padding: 20px; }"
  showValidation={true}
  disabled={false}
/>

Validation

The SDK includes a comprehensive validation engine.

Validate Entire Form

import { validateForm } from '@robertotaylor0/mediform-client-sdk';

const result = validateForm(formDefinition, formData);

if (!result.valid) {
  console.log('Errors:', result.errors);
  // result.errors = { fieldId: ['error message 1', 'error message 2'] }
}

Validate Single Field

import { validateField } from '@robertotaylor0/mediform-client-sdk';

const errors = validateField(formDefinition, 'patientName', 'John Doe');

if (errors.length > 0) {
  console.log('Field errors:', errors);
}

Supported Validation Rules

  • ✅ Required fields
  • ✅ Min/max length (strings)
  • ✅ Min/max value (numbers)
  • ✅ Pattern matching (regex)
  • ✅ Decimal places (numbers)
  • ✅ Custom validation rules
  • ✅ Input masking (phone, SSN, date, etc.)

Form Auto-Population (AI Extraction)

The SDK includes AI-powered form auto-population that can extract values from images of completed forms or from text containing form responses.

Quick Example

import { MediFormClient, convertExtractionsToFormData } from '@robertotaylor0/mediform-client-sdk';

const client = new MediFormClient({
  apiKey: 'mk_your_api_key',
  baseUrl: 'https://your-instance.com',
});

// Get form definition
const form = await client.getForm('patient-intake');

// Extract values from an image
const extractionResult = await client.extractFormValues('patient-intake', {
  completedFormImageUri: imageDataUri, // data:image/png;base64,...
});

// Convert to form data format
const formData = convertExtractionsToFormData(
  extractionResult.extractions,
  form.formDefinition
);

// Render with pre-populated data
<FormRenderer
  formDefinition={form.formDefinition}
  initialValues={formData}
  onSubmit={handleSubmit}
/>

Extract from Image

Perfect for scanning paper forms or photos of completed forms:

// Read image file as data URI
const fileInput = document.querySelector('input[type="file"]');
const file = fileInput.files[0];

const reader = new FileReader();
reader.onload = async (e) => {
  const dataUri = e.target.result as string;

  const result = await client.extractFormValues('form-id', {
    completedFormImageUri: dataUri,
  });

  // Filter by confidence (only include high-confidence extractions)
  const filtered = filterByConfidence(result.extractions, 0.7);

  // Apply to form
  const formData = convertExtractionsToFormData(filtered, form.formDefinition);
};

reader.readAsDataURL(file);

Extract from Text

Perfect for clinical notes, dictation, or typed responses:

const clinicalNote = `
  Patient: John Doe
  Age: 45 years old
  Chief complaint: Fever and cough for 3 days
  Temperature: 101.2°F
  Blood pressure: 120/80
  Medications: None
`;

const result = await client.extractFormValues('visit-note', {
  completedFormText: clinicalNote,
});

// Convert and apply
const formData = convertExtractionsToFormData(
  result.extractions,
  form.formDefinition
);

Extraction Utilities

The SDK provides helper functions for working with extracted data:

convertExtractionsToFormData()

Converts extraction results to the format expected by FormRenderer:

import { convertExtractionsToFormData } from '@robertotaylor0/mediform-client-sdk';

const formData = convertExtractionsToFormData(
  extractionResult.extractions,
  form.formDefinition
);

// Handles type conversions:
// - Checkboxes → arrays
// - Yes/No → booleans
// - Numbers → numeric types
// - Dates → ISO strings

filterByConfidence()

Filter extractions by confidence threshold:

import { filterByConfidence } from '@robertotaylor0/mediform-client-sdk';

// Only keep extractions with 70%+ confidence
const highConfidence = filterByConfidence(result.extractions, 0.7);

// Only keep extractions with 90%+ confidence
const veryHighConfidence = filterByConfidence(result.extractions, 0.9);

getLowConfidenceFields()

Get list of fields that need manual review:

import { getLowConfidenceFields } from '@robertotaylor0/mediform-client-sdk';

// Get fields with confidence < 70%
const needsReview = getLowConfidenceFields(result.extractions, 0.7);

console.log('Please review these fields:', needsReview);
// ['field1', 'field3', 'field7']

validateExtractions()

Validate extracted values against form rules:

import { validateExtractions } from '@robertotaylor0/mediform-client-sdk';

const errors = validateExtractions(
  result.extractions,
  form.formDefinition
);

Object.entries(errors).forEach(([fieldId, errorMsg]) => {
  if (errorMsg) {
    console.log(`${fieldId}: ${errorMsg}`);
  }
});

extractFieldLabels()

Get human-readable labels for all fields:

import { extractFieldLabels } from '@robertotaylor0/mediform-client-sdk';

const labels = extractFieldLabels(form.formDefinition);

// Use for display in review UI
Object.entries(result.extractions).forEach(([fieldId, extraction]) => {
  console.log(`${labels[fieldId]}: ${extraction.value}`);
});

Complete Extraction Example

Full example with confidence filtering and validation:

import {
  MediFormClient,
  FormRenderer,
  convertExtractionsToFormData,
  filterByConfidence,
  getLowConfidenceFields,
  validateExtractions,
  extractFieldLabels,
} from '@robertotaylor0/mediform-client-sdk';

function AutoPopulateForm() {
  const [form, setForm] = useState(null);
  const [formData, setFormData] = useState({});
  const [lowConfidenceFields, setLowConfidenceFields] = useState([]);

  const handleImageUpload = async (file: File) => {
    // Convert to data URI
    const dataUri = await fileToDataUri(file);

    // Extract values
    const result = await client.extractFormValues(form.id, {
      completedFormImageUri: dataUri,
    });

    // Only use high-confidence extractions (70%+)
    const filtered = filterByConfidence(result.extractions, 0.7);

    // Identify fields that need review
    const needsReview = getLowConfidenceFields(result.extractions, 0.7);
    setLowConfidenceFields(needsReview);

    // Validate extracted values
    const errors = validateExtractions(filtered, form.formDefinition);

    // Convert to form data format
    const data = convertExtractionsToFormData(filtered, form.formDefinition);
    setFormData(data);

    // Show summary
    const labels = extractFieldLabels(form.formDefinition);
    const summary = Object.entries(result.extractions).map(([id, ext]) => ({
      label: labels[id],
      value: ext.value,
      confidence: ext.confidence,
      error: errors[id],
    }));

    console.log('Extraction summary:', summary);
  };

  return (
    <div>
      <input
        type="file"
        accept="image/*,application/pdf"
        onChange={(e) => handleImageUpload(e.target.files[0])}
      />

      {lowConfidenceFields.length > 0 && (
        <div className="warning">
          Please review these fields: {lowConfidenceFields.join(', ')}
        </div>
      )}

      {form && (
        <FormRenderer
          formDefinition={form.formDefinition}
          initialValues={formData}
          onSubmit={handleSubmit}
        />
      )}
    </div>
  );
}

Extraction Response Format

The extraction result includes confidence scores and metadata:

interface ExtractionResult {
  extractions: {
    [fieldId: string]: {
      value: any;                    // Extracted value
      confidence: number;             // 0.0 to 1.0
      originalText?: string | null;  // Original text from image/document
      alternatives?: any[];          // Alternative interpretations
    };
  };
}

Example response:

{
  "extractions": {
    "patientName": {
      "value": "John Doe",
      "confidence": 0.95,
      "originalText": "John Doe"
    },
    "age": {
      "value": 45,
      "confidence": 0.92,
      "originalText": "45"
    },
    "symptoms": {
      "value": ["fever", "cough"],
      "confidence": 0.88,
      "originalText": "fever, cough"
    }
  }
}

Best Practices

  1. Always filter by confidence - Only auto-populate fields with high confidence (0.7+)
  2. Flag low-confidence fields - Highlight fields that need manual review
  3. Validate extracted data - Check against form validation rules before submitting
  4. Show original text - Display originalText for user verification
  5. Allow manual override - Let users correct any mistakes
  6. Test with real data - Handwriting and image quality vary greatly

Supported Input Types

  • Images: PNG, JPEG, GIF, WebP (as data URIs)
  • PDFs: Single or multi-page PDFs (converted to images internally)
  • Text: Plain text, clinical notes, dictation, Q&A format

Theming

Customize the appearance of forms to match your EHR's design.

const theme = {
  colors: {
    primary: '#007bff',      // Primary buttons, focus states
    secondary: '#6c757d',    // Secondary elements
    error: '#dc3545',        // Error messages, validation
    success: '#28a745',      // Success states
    background: '#ffffff',   // Form background
    border: '#dee2e6',       // Input borders
  },
  fonts: {
    family: 'Inter, system-ui, sans-serif',
    size: '16px',
  },
  spacing: {
    field: '1rem',    // Space between fields
    section: '2rem',  // Space between sections
  },
};

<FormRenderer formDefinition={form} theme={theme} />

Custom Components

Replace default field components with your own.

import { FieldProps } from '@robertotaylor0/mediform-client-sdk';

function MyCustomTextField({ element, value, onChange, error }: FieldProps) {
  return (
    <div>
      <label>{element.properties?.label}</label>
      <input
        type="text"
        value={value || ''}
        onChange={(e) => onChange(e.target.value)}
        className={error ? 'error' : ''}
      />
      {error && <span className="error-message">{error}</span>}
    </div>
  );
}

<FormRenderer
  formDefinition={form}
  customComponents={{
    text: MyCustomTextField,
  }}
/>

Error Handling

The SDK throws MediFormError for API errors.

import { MediFormClient, MediFormError } from '@robertotaylor0/mediform-client-sdk';

try {
  const form = await client.getForm('invalid-id');
} catch (error) {
  if (error instanceof MediFormError) {
    console.log('Error code:', error.code);
    console.log('Status:', error.statusCode);
    console.log('Message:', error.message);
    console.log('Details:', error.details);
  }
}

Common Error Codes:

  • MISSING_API_KEY - API key not provided
  • INVALID_API_KEY - API key is invalid or expired
  • RATE_LIMIT_EXCEEDED - Too many requests
  • NOT_FOUND - Form not found
  • FORBIDDEN - Access denied to form
  • CORS_FORBIDDEN - Origin not allowed
  • INTERNAL_ERROR - Server error

TypeScript Support

The SDK is written in TypeScript and includes full type definitions.

import type {
  FormDefinition,
  FormListItem,
  FormElement,
  FormData,
  ValidationResult,
  ThemeConfig,
  ExtractedField,
  ExtractionResult,
  ExtractionInput,
  PaginatedResponse,
} from '@robertotaylor0/mediform-client-sdk';

// All types are exported and available

Key Type Definitions

FormListItem

Returned by listForms():

interface FormListItem {
  id: string;
  templateId: string;
  version: number;
  metadata: {
    name: string;
    description?: string;
    tags?: string[];
    category?: string;
  };
  publishedAt: string;
}

FormDefinition

Returned by getForm() and getFormVersion():

interface FormDefinition {
  id: string;
  templateId: string;
  version: number;
  metadata: {
    name: string;
    description?: string;
    tags?: string[];
    category?: string;
  };
  formDefinition: FormElement;  // The actual form structure
  customCss: string;
  publishedAt: string;
}

PaginatedResponse

Returned by listForms():

interface PaginatedResponse<T> {
  items: T[];
  pagination: {
    page: number;
    limit: number;
    total: number;
    totalPages: number;
    hasNext: boolean;
    hasPrev: boolean;
  };
}

ExtractedField

Part of extraction results:

interface ExtractedField {
  value: any;
  confidence: number;      // 0.0 to 1.0
  originalText?: string | null;
  alternatives?: any[];
}

React Integration Example

Complete example with loading states and error handling:

import React, { useState, useEffect } from 'react';
import { MediFormClient, FormRenderer, MediFormError } from '@robertotaylor0/mediform-client-sdk';
import '@robertotaylor0/mediform-client-sdk/dist/index.css';

const client = new MediFormClient({
  apiKey: process.env.REACT_APP_MEDIFORM_API_KEY!,
  baseUrl: process.env.REACT_APP_MEDIFORM_URL!,
});

function FormPage({ formId }: { formId: string }) {
  const [form, setForm] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    client.getForm(formId)
      .then(setForm)
      .catch((err) => {
        if (err instanceof MediFormError) {
          setError(err.message);
        } else {
          setError('Failed to load form');
        }
      })
      .finally(() => setLoading(false));
  }, [formId]);

  const handleSubmit = async (data) => {
    try {
      await saveToEHR(data);
      alert('Form submitted successfully!');
    } catch (err) {
      alert('Failed to submit form');
    }
  };

  if (loading) return <div>Loading form...</div>;
  if (error) return <div>Error: {error}</div>;
  if (!form) return <div>Form not found</div>;

  return (
    <div className="form-container">
      <h1>{form.metadata.name}</h1>
      <FormRenderer
        formDefinition={form.formDefinition}
        customCss={form.customCss}
        onSubmit={handleSubmit}
      />
    </div>
  );
}

Browser Support

  • Chrome/Edge: Latest 2 versions
  • Firefox: Latest 2 versions
  • Safari: Latest 2 versions
  • Mobile browsers: iOS Safari 13+, Chrome Android 80+

Performance Tips

  1. Enable Caching - Reduces API calls (enabled by default)
  2. Use Form Versions - Pin to specific versions for stability
  3. Lazy Load - Only load forms when needed
  4. Bundle Size - The SDK is tree-shakeable (use named imports)
  5. CDN for Styles - Load CSS from CDN for faster initial load

Security Best Practices

  1. Never expose API keys in client-side code

    • Use environment variables
    • Proxy requests through your backend if needed
  2. Validate on server - Always validate form submissions on your server

    • Client-side validation can be bypassed
  3. Sanitize data - Clean user input before storing in your EHR

    • Use a library like DOMPurify for HTML content
  4. Use HTTPS - Always use HTTPS in production

Troubleshooting

"Invalid API Key" Error

  • Check that your API key is correct
  • Verify the key hasn't been revoked
  • Check if the key has expired

"CORS Error"

  • Ensure your domain is whitelisted in the API key settings
  • Check that you're using HTTPS in production

"Rate Limit Exceeded"

  • Reduce request frequency
  • Implement request throttling
  • Contact support to increase limits

Forms Not Loading

  • Check network connectivity
  • Verify the form ID is correct
  • Check if the form is published and API-enabled
  • Look at browser console for errors

Common Mistakes

1. Accessing Form Properties Incorrectly

INCORRECT:

const forms = await client.listForms();
console.log(forms.items[0].name); // undefined!
console.log(forms.items[0].description); // undefined!

CORRECT:

const forms = await client.listForms();
console.log(forms.items[0].metadata.name); // Works!
console.log(forms.items[0].metadata.description); // Works!

Why: Form properties like name, description, category, and tags are nested inside the metadata object. Only id, templateId, version, and publishedAt are at the root level.

2. Wrong CSS Import Path

INCORRECT:

import '@robertotaylor0/mediform-client-sdk/dist/styles.css';

CORRECT:

import '@robertotaylor0/mediform-client-sdk/dist/index.css';

Why: The published package contains index.css, not styles.css.

3. Assuming Latest Version

Always specify the version explicitly in production:

{
  "dependencies": {
    "@robertotaylor0/mediform-client-sdk": "1.0.0"
  }
}

Why: Pinning versions prevents unexpected breaking changes in production.

License

MIT

Support

Changelog

v1.0.0 (Current)

  • ✅ Form fetching and listing with pagination
  • ✅ React FormRenderer component with full theming support
  • ✅ AI-powered form auto-population from images and text
  • ✅ Extraction utility functions (convertExtractionsToFormData, filterByConfidence, getLowConfidenceFields, etc.)
  • ✅ Comprehensive validation engine with field-level and form-level validation
  • ✅ Response caching for improved performance
  • ✅ Full TypeScript definitions including FormListItem, FormDefinition, ExtractedField, ExtractionInput, ExtractionResult, and PaginatedResponse types
  • ✅ Conditional logic evaluation
  • ✅ Custom component support
  • ✅ WCAG 2.1 AA accessibility compliance
  • ✅ Comprehensive error handling with MediFormError class

Made with ❤️ by the MediForm Team