Web SDK
The Tiro.health Web SDK provides native Web Components for integrating FHIR-based form filling capabilities into any web application.
Looking for the legacy SDK with the imperative mount()/unmount() API? See the legacy Web SDK documentation.
The SDK is built with native Web Components that work with any JavaScript framework or vanilla JavaScript:
<tiro-form-filler>: Interactive form rendering with full SDC support<tiro-narrative>: Clinical narrative generation from responses<tiro-validation-report>: Real-time validation error display
Installation
Choose one of the following installation methods:
CDN (Recommended for Quick Start)
The fastest way to get started. No build tools required - just add two lines to your HTML. Ideal for proof of concepts and rapid prototyping.
<link rel="stylesheet" href="https://cdn.tiro.health/sdk/latest/tiro-web-sdk.css">
<script src="https://cdn.tiro.health/sdk/latest/tiro-web-sdk.iife.js"></script>
NPM
For production applications with build tools:
npm install @tiro-health/web-sdk
Import the SDK and its stylesheet:
import '@tiro-health/web-sdk'
import '@tiro-health/web-sdk/style.css'
CSS is required. The Web Components will not render correctly without the stylesheet.
Bundle Options
| Bundle | Import | Use When |
|---|---|---|
| Full | @tiro-health/web-sdk | Your app doesn't use React |
| Lite | @tiro-health/web-sdk/lite | Your app already has React 18 |
Quick Start
<tiro-form-filler
questionnaire="http://templates.tiro.health/example|1.0.0">
</tiro-form-filler>
This renders an interactive form based on the FHIR Questionnaire. Users can fill in fields, and the component manages all form state internally.
With Narrative and Validation
Components link together using the for attribute:
<tiro-form-filler
id="patient-form"
questionnaire="http://templates.tiro.health/patient-intake|2.0.0"
sdc-endpoint-address="https://sdc.tiro.health/fhir/r5">
</tiro-form-filler>
<tiro-narrative for="patient-form"></tiro-narrative>
<tiro-validation-report for="patient-form"></tiro-validation-report>
This displays three linked components: the form, a live-updating clinical narrative generated from the responses, and validation errors that appear when required fields are missing or invalid.
Inline Questionnaire
For simple forms or testing, you can embed the questionnaire definition directly in HTML using a <script> tag with type="application/fhir+json":
<tiro-form-filler id="inline-form">
<script type="application/fhir+json" slot="questionnaire">
{
"resourceType": "Questionnaire",
"status": "draft",
"title": "Feedback Form",
"item": [
{
"linkId": "name",
"type": "string",
"text": "What is your name?"
},
{
"linkId": "feedback",
"type": "text",
"text": "Any feedback?"
}
]
}
</script>
</tiro-form-filler>
<script>
const form = document.getElementById('inline-form')
form.addEventListener('tiro-submit', (e) => {
console.log('Submitted:', e.detail.response)
})
</script>
This renders a simple two-field form with a text input and a textarea. When submitted, the FHIR QuestionnaireResponse is logged to the console.
Inline questionnaires don't require an SDC endpoint for basic rendering, but advanced features like population and extraction still need a backend.
Components
<tiro-form-filler>
The primary component for rendering FHIR Questionnaires.
Attributes:
questionnaire- Canonical URL with version (e.g.,url|version)sdc-endpoint-address- SDC FHIR server URLlaunch-context- JSON object with FHIR resources (Patient, Encounter)read-only- Disable form editing
Methods:
getResponse()- Get current QuestionnaireResponsesubmit()- Programmatically submit the formcheckValidity()- Check if form is valid
Events:
tiro-ready- Fired when the questionnaire is loaded.e.detail.questionnairetiro-update- Fired on every form change.e.detail.responsetiro-submit- Fired when the form is submitted.e.detail.responsetiro-validate- Fired after validation.e.detail.isValid,e.detail.operationOutcometiro-error- Fired on errors.e.detail.error
<tiro-narrative>
Generates human-readable clinical narratives from questionnaire responses.
Attributes:
for- ID of the<tiro-form-filler>to link to
<tiro-narrative for="my-form"></tiro-narrative>
Events:
tiro-update- Fired when narrative content changes.e.detail.narrative
<tiro-validation-report>
Displays FHIR OperationOutcome validation results. Automatically hides when valid.
Attributes:
for- ID of the<tiro-form-filler>to link to
<tiro-validation-report for="my-form"></tiro-validation-report>
Events:
tiro-update- Fired when validation results change.e.detail.operationOutcome
Custom Authentication
For applications requiring custom authentication (OAuth, JWT, session tokens), create an SDCClient programmatically instead of using the sdc-endpoint-address attribute.
Basic Setup
import { SDCClient } from '@tiro-health/web-sdk'
const sdcClient = new SDCClient({
baseUrl: 'https://sdc.example.com/fhir/r5',
auth: async () => {
const token = await getAccessToken() // Your auth logic
return `Bearer ${token}`
}
})
const form = document.querySelector('tiro-form-filler')
form.sdcClient = sdcClient
The auth function is called before each request, allowing you to handle token refresh automatically.
With Interceptors
Add request/response interceptors for logging or error handling:
const sdcClient = new SDCClient({
baseUrl: 'https://sdc.example.com/fhir/r5',
auth: async () => `Bearer ${await getAccessToken()}`
})
// Log outgoing requests
sdcClient.interceptors.request.use(async (req) => {
console.log('Request:', req.method, req.url)
return req
})
// Handle auth errors
sdcClient.interceptors.response.use(async (res) => {
if (res.status === 401) {
// Trigger re-authentication
}
return res
})
document.querySelector('tiro-form-filler').sdcClient = sdcClient
Framework Integration
Web Components work with any framework using standard DOM APIs.
React
import '@tiro-health/web-sdk'
import '@tiro-health/web-sdk/style.css'
import { useRef, useEffect } from 'react'
function FormPage() {
const formRef = useRef(null)
useEffect(() => {
const form = formRef.current
const handleSubmit = (e) => console.log(e.detail.response)
form.addEventListener('tiro-submit', handleSubmit)
return () => form.removeEventListener('tiro-submit', handleSubmit)
}, [])
return (
<tiro-form-filler
ref={formRef}
questionnaire="http://example.com/q|1.0.0"
sdc-endpoint-address="https://sdc.example.com/fhir/r5"
/>
)
}
Angular
Add CUSTOM_ELEMENTS_SCHEMA to your module or component:
import { CUSTOM_ELEMENTS_SCHEMA, Component } from '@angular/core'
import '@tiro-health/web-sdk'
import '@tiro-health/web-sdk/style.css'
@Component({
selector: 'app-form',
schemas: [CUSTOM_ELEMENTS_SCHEMA],
template: `
<tiro-form-filler
[attr.questionnaire]="questionnaire"
[attr.sdc-endpoint-address]="sdcEndpoint"
(tiro-submit)="onSubmit($event)">
</tiro-form-filler>
`
})
export class FormComponent {
questionnaire = 'http://example.com/q|1.0.0'
sdcEndpoint = 'https://sdc.example.com/fhir/r5'
onSubmit(event: CustomEvent) {
console.log(event.detail.response)
}
}
Vanilla JavaScript
import '@tiro-health/web-sdk'
import '@tiro-health/web-sdk/style.css'
const form = document.createElement('tiro-form-filler')
form.setAttribute('questionnaire', 'http://example.com/q|1.0.0')
form.setAttribute('sdc-endpoint-address', 'https://sdc.example.com/fhir/r5')
form.addEventListener('tiro-submit', (e) => console.log(e.detail.response))
document.body.appendChild(form)
For detailed API reference, see the npm package documentation.