@clinikapi/react
v0.3.1
Published
Pre-built clinical UI widgets for React using the ClinikAPI proxy pattern. 14 responsive, themeable components built on shadcn/ui + Radix.
Maintainers
Readme
@clinikapi/react
Pre-built clinical UI widgets for React, built on shadcn/ui + Radix. Displays patient data, vitals, appointments, prescriptions, and more — all through a secure proxy pattern that never exposes your API key.
Install
npm install @clinikapi/reactThen import the stylesheet once, anywhere in your app:
import '@clinikapi/react/styles.css';That's the whole setup. The stylesheet is self-contained and every rule in it is scoped to the widgets' own root element, so it cannot restyle your pages — and you don't need Tailwind, or any particular build setup, to use it.
Upgrading from 0.2.x? The widgets were rebuilt on shadcn/ui. Add the
styles.cssimport above — without it they render unstyled. No component props changed.
How It Works
These widgets run in the browser and communicate with your backend proxy — never directly with ClinikAPI. Your backend calls the SDK with your secret key, and the widget displays the results.
Browser Widget → Your Backend Proxy → @clinikapi/sdk → ClinikAPIQuick Start
1. Set up a backend proxy
// app/api/clinik/route.ts (Next.js)
import { Clinik } from '@clinikapi/sdk';
const clinik = new Clinik(process.env.CLINIKAPI_SECRET_KEY!);
export async function POST(req: Request) {
const { action, data } = await req.json();
// Authenticate the user with YOUR auth system first
switch (action) {
case 'patients.read':
return Response.json(await clinik.patients.read(data.id, { include: data.include }));
case 'patients.create':
return Response.json(await clinik.patients.create(data));
case 'appointments.create':
return Response.json(await clinik.appointments.create(data));
case 'prescriptions.create':
return Response.json(await clinik.prescriptions.create(data));
case 'notes.create':
return Response.json(await clinik.notes.create(data));
case 'intakes.submit':
return Response.json(await clinik.intakes.submit(data));
case 'consents.sign':
return Response.json(await clinik.consents.sign(data));
case 'observations.create':
return Response.json(await clinik.observations.create(data));
case 'labs.create':
return Response.json(await clinik.labs.create(data));
default:
return Response.json({ error: 'Unknown action' }, { status: 400 });
}
}2. Use a widget
import { PatientDashboard } from '@clinikapi/react';
export default function PatientPage({ patientId }: { patientId: string }) {
return (
<PatientDashboard
proxyUrl="/api/clinik"
patientId={patientId}
/>
);
}Available Widgets
| Widget | Description | Key Fields |
|--------|-------------|------------|
| PatientDashboard | Full patient overview — demographics, encounters, vitals, meds, labs, notes | 3 themes (light, dark, glassmorphism) |
| AppointmentScheduler | Book appointments | date, time, type, serviceType, specialty, priority, description |
| PrescriptionForm | Write prescriptions | medication, dosage, priority, category, courseOfTherapy, substitution |
| NoteEditor | Clinical note editor | title, content, type, docStatus, category, practiceSetting |
| IntakeForm | Patient intake questionnaire | items with text, boolean, integer, coded, quantity answers |
| ConsentManager | Consent signing | scope, category, verification, provision rules |
| VitalsWidget | Record vital signs | heart rate, blood pressure |
| LabResultsWidget | Order lab reports | LOINC codes, category, effectiveDateTime |
| PrescriptionWidget | Quick medication entry | medication name, status |
| ConditionTracker | Record conditions/diagnoses | code, clinicalStatus, severity, onset |
| AllergyRecorder | Record allergies/intolerances | allergen, type, category, criticality, reaction |
| ImmunizationLogger | Log immunizations | vaccine, site, route, lot number, manufacturer |
| CarePlanBuilder | Create care plans | title, description, status, intent, category |
| GoalSetter | Set patient goals | description, lifecycle, achievement, priority, target date |
Common Props
All widgets accept:
| Prop | Type | Required | Description |
|------|------|----------|-------------|
| proxyUrl | string | Yes | Your backend proxy endpoint (or 'demo' for demo mode) |
| patientId | string | Yes | Patient ID |
| theme | 'light' \| 'dark' \| 'glassmorphism' \| 'inherit' | No | Colour theme — see below |
| className | string | No | Extra classes on the widget root |
Theming
Widgets read a set of --ck-* CSS custom properties. Override any of them to
match your brand — the values are HSL channels, the same convention shadcn/ui
uses:
.clinik-root {
--ck-primary: 173 80% 40%; /* teal */
--ck-radius: 0.375rem; /* squarer corners */
}The full token set is --ck-background, --ck-foreground, --ck-card,
--ck-popover, --ck-primary, --ck-secondary, --ck-muted, --ck-accent,
--ck-destructive, --ck-success, --ck-border, --ck-input, --ck-ring,
--ck-radius (each with a matching -foreground where it applies).
Already using shadcn/ui? Pass theme="inherit" and the widgets map straight
onto your app's own --primary / --border / --radius variables, so they
match your design system with no configuration:
<PatientDashboard proxyUrl="/api/clinik" theme="inherit" />This is opt-in rather than automatic, because an app that isn't using shadcn/ui
may well define --primary in a different format (a hex, say), which would
render the widgets incorrectly.
Demo Mode
Set proxyUrl="demo" to run any widget without a backend — no API calls made.
<PatientDashboard proxyUrl="demo" />
<AppointmentScheduler proxyUrl="demo" patientId="demo-patient" />Security
- Widgets never receive your API key
- All data flows through your backend proxy
- You control authentication and authorization on your proxy endpoint
proxyUrlis validated to prevent open redirect attacks — must be relative path or same-origin
Requirements
- React 18 or 19
- A backend proxy that calls
@clinikapi/sdk
Documentation
Full docs at docs.clinikapi.com/components
License
MIT
