Package Exports
- @symbionix/curaport
- @symbionix/curaport/app-shell
- @symbionix/curaport/appointment
- @symbionix/curaport/consent
- @symbionix/curaport/consultation
- @symbionix/curaport/core
- @symbionix/curaport/dashboard
- @symbionix/curaport/fhir-explorer
- @symbionix/curaport/fixtures
- @symbionix/curaport/med-rec
- @symbionix/curaport/messaging
- @symbionix/curaport/notifications
- @symbionix/curaport/package.json
- @symbionix/curaport/prescription
- @symbionix/curaport/provider-directory
- @symbionix/curaport/questionnaire
- @symbionix/curaport/referral
- @symbionix/curaport/smart-intake
- @symbionix/curaport/styles.css
- @symbionix/curaport/tailwind-preset
- @symbionix/curaport/task
- @symbionix/curaport/ui
Readme
@symbionix/curaport
Embeddable React components and a design system for FHIR-aware healthcare apps. Powers the Symbionix Patient Portal and is published for any third-party EMR or portal to embed.
Install
pnpm add @symbionix/curaport @tanstack/react-query react react-dom
# or
npm install @symbionix/curaport @tanstack/react-query react react-domThen bring the stylesheet in once at your app root:
import "@symbionix/curaport/styles.css";Quick start
import {
PortalProvider,
PortalClient,
PatientPortal,
} from "@symbionix/curaport";
import "@symbionix/curaport/styles.css";
const client = new PortalClient({
apiUrl: process.env.NEXT_PUBLIC_PORTAL_API!,
getAccessToken: async () =>
fetch("/api/portal-token").then((r) => r.text()),
});
export default function App() {
return (
<PortalProvider client={client}>
<PatientPortal
resourceId="123"
fhirServerUrl="https://hapi.example.com/fhir"
/>
</PortalProvider>
);
}Subpath exports
The package ships several entry points so consumers only pull in what they need:
| Import | Contents |
|---|---|
@symbionix/curaport |
Top-level: PatientPortal, PatientSummary, PatientTimeline, PortalProvider, PortalClient, and every clinical section (AllergiesList, ProblemList, MedicationsList, VitalSigns, VitalSignsChart, ProcedureHistory, ImmunizationHistory, EncounterList, DiagnosticReportsList, CareTeam, PatientProfile, LabResults, LabResultGraph, HealthDashboard, NotificationsPanel, MessagingInbox, AppointmentList, ResourceDetailModal, StatsCards, PatientSelector) plus FHIR type aliases and helpers. |
@symbionix/curaport/ui |
Design-system primitives: Button, Card, Badge, Input, Label, Dialog, Select, Tabs, Tooltip, Skeleton, Avatar, Separator, Table, EmptyState, ThemeProvider, cn. |
@symbionix/curaport/app-shell |
Layout primitives: AppShell, Sidebar, Topbar, Breadcrumb, PageHeader. |
@symbionix/curaport/dashboard |
Dashboard widgets: StatCard, ActivityFeed, QuickActions, AppointmentCard, RosterTable, MetricRing, ChartCard. |
@symbionix/curaport/fixtures |
Canonical FHIR sample data for demos, stories, and tests. |
@symbionix/curaport/tailwind-preset |
Tailwind config preset — extend your tailwind.config to share tokens. |
@symbionix/curaport/styles.css |
Compiled stylesheet for non-Tailwind consumers. |
Theming
All colours, spacing, and radii are driven by CSS variables prefixed --pp-*. Override any of them on a root element to rebrand without rebuilding:
:root {
--pp-primary: 200 80% 45%; /* HSL triplet, no hsl() wrapper */
--pp-radius: 0.5rem;
}The library ships a clinical-teal default with semantic colours for success / warning / destructive / info, plus a dark mode (toggle by setting data-theme="dark" on a root element, or via the ThemeProvider component).
Tailwind apps
If your app already uses Tailwind, extend the preset to share tokens automatically:
// tailwind.config.ts
import preset from "@symbionix/curaport/tailwind-preset";
export default {
presets: [preset],
content: [
"./src/**/*.{ts,tsx}",
"./node_modules/@symbionix/curaport/dist/**/*.{js,cjs}",
],
};The library's compiled stylesheet is still required for the base layer + CSS variables — import it once at app root.
What ships
- 22+ clinical components covering allergies, problems, medications, vitals (with trend chart), procedures, immunizations, encounters, diagnostic reports, care team, profile, and unified timeline + summary + top-level portal.
- Patient experience widgets: appointments, lab results browser + trend graph, notifications feed, messaging inbox, health dashboard composite.
- Design system: 15 primitives wrapping Radix UI + a CSS-variable-driven theme.
- App shell: sidebar nav, topbar, breadcrumb, page header — a complete chrome for any role-based app.
- Dashboard widgets: stat cards, activity feed, chart card, metric ring, roster table, appointment card.
All exports are TypeScript-first with declaration files, support tree-shaking, and ship sourcemaps.
Peer dependencies
| Peer | Required |
|---|---|
react |
≥ 18 |
react-dom |
≥ 18 |
@tanstack/react-query |
≥ 5 |
Internally we use Radix UI primitives, Framer Motion, Recharts, lucide-react, sonner, class-variance-authority, clsx, tailwind-merge, and date-fns — these are bundled deps, not peers.
SSR
Every component is SSR-safe (no window access at module load). Server components can render top-level views, though interactive components (filters, dialogs) are marked "use client".
Versioning
Semver. The package is currently in 1.0.0-alpha.* — breaking changes possible between alphas. Will graduate to 1.0.0 once the demo EMR has consumed the published artifact end-to-end.
License
UNLICENSED — internal Symbionix package. Contact the Symbionix team for licensing terms before redistribution.
Contributing / development
The library lives in the patient-portal-revamp monorepo. To work on it locally:
git clone https://github.com/symbionix/patient-portal-revamp.git
cd patient-portal-revamp/components
pnpm install
pnpm storybook # http://localhost:6006
pnpm test
pnpm build # ESM + CJS + .d.ts + styles.cssSee CHANGELOG.md for the release history.