All articles
Engineering

How to Build a Patient Intake Form in React (with Consent)

A step-by-step guide to building a patient intake form in React using pre-built, FHIR-native components — structured intake answers and consent signing, with no form plumbing to write.

ClinikAPI TeamApril 26, 20268 min read
How to Build a Patient Intake Form in React (with Consent)

Patient intake looks like a simple form — until you build it. You're not just collecting text; you're capturing structured clinical data and legally meaningful consent, and both need to be stored correctly so they're searchable and connected to the patient's record. Build that from scratch and you're writing fields, validation, FHIR mapping, and a consent flow. With two pre-built components, you skip all of it. This guide shows you how, step by step.

The toolkit we recommend is ClinikAPI — a FHIR-native platform with a React component library. Here's why we suggest it up front:

  • Free to start: Get your API keys in seconds — no credit card needed.
  • Two components: IntakeForm for intake, ConsentManager for consent.
  • Structured data: Answers are stored as FHIR, not loose text.
  • Themeable: A theme prop makes them match your app.
  • Compliant: HIPAA-compliant, SOC 2-audited, with a signed BAA.

Quick Answer

To build a patient intake form in React, use pre-built FHIR-native components instead of hand-rolling the form. ClinikAPI's IntakeForm renders an intake questionnaire and stores the answers as structured FHIR data, and ConsentManager handles consent signing and management as a FHIR Consent record. You add each component, point it at a small route on your own backend (the proxyUrl), and pass a patientId. You don't build the fields, validation, FHIR mapping, or consent flow — and the data is searchable and connected to the patient's record from the start. The proxy route keeps your secret key server-side, and a theme prop makes the components match your app.

See intake & consent components live

The ClinikAPI UI Library has IntakeForm, ConsentManager, and 12 more clinical components you can drop into any React app — free sandbox included.
Explore the UI Library

Intake is two jobs, not one

When you break intake down, it's really two tasks:

  1. Collect structured clinical info — the questionnaire, stored as data you can use.
  2. Capture consent — a legally meaningful, verifiable record.

Treating these as "just a form" is where teams get into trouble: unstructured answers and a consent checkbox that isn't a real record. Two purpose-built components solve both properly.

Step 1: Install and set up the proxy

Install the frontend components and the backend SDK, then create the proxy route (the same pattern every ClinikAPI component uses):

npm install @clinikapi/react @clinikapi/sdk

The intake and consent components POST { action, data } to your route; you route each action to the SDK. For intake you need the intakes.submit and consents.sign actions:

// app/api/clinik/route.ts — server-only
import { Clinik } from '@clinikapi/sdk'

const clinik = new Clinik(process.env.CLINIKAPI_SECRET_KEY!) // clk_live_… / clk_test_…

export async function POST(req: Request) {
  const { action, data } = await req.json()
  // Authenticate + authorize the user for data.patientId first.
  try {
    switch (action) {
      case 'intakes.submit':
        return Response.json(await clinik.intakes.submit(data))
      case 'consents.sign':
        return Response.json(await clinik.consents.sign(data))
      default:
        return Response.json({ error: 'Unknown action' }, { status: 400 })
    }
  } catch {
    return Response.json({ error: 'Request failed' }, { status: 500 })
  }
}
Caution

The SDK is server-side only — your clk_live_… key never reaches the browser. Auth is your job in this route: confirm the signed-in user may submit intake/consent for data.patientId before calling the SDK. (See the dashboard tutorial for the full route, response shape, and demo mode.)

Note

Skip the backend entirely while prototyping: set proxyUrl="demo" on either component to run it with mock data and no API calls.

Step 2: Add the intake form

The IntakeForm component renders the questionnaire and stores answers as structured FHIR — no fields or validation to write:

import { IntakeForm } from '@clinikapi/react'

export function Intake({ patientId }: { patientId: string }) {
  return (
    <IntakeForm
      proxyUrl="/api/clinik"
      patientId={patientId}
      theme="light"
    />
  )
}

Because the answers are stored as structured FHIR, the intake is part of the patient's record from the moment it's submitted — searchable and connected, not a blob you'll have to parse later.

Step 3: Add consent

Consent isn't a checkbox — it's a record. The ConsentManager component handles signing and management, including the scope of consent, verification, and provisions, and stores it as a FHIR Consent record:

import { ConsentManager } from '@clinikapi/react'

<ConsentManager
  proxyUrl="/api/clinik"
  patientId={patientId}
  theme="light"
/>

Now consent is a proper, verifiable part of the chart — which matters legally and operationally.

What you skipped

You skippedBecause the components do it
Building form fieldsIntakeForm renders the questionnaire
Validation and structureAnswers stored as structured FHIR
FHIR mappingHandled automatically
A real consent flowConsentManager stores a FHIR Consent record

You placed two components and provided a patient ID. That's it.

Product Insight: Why ClinikAPI Fits Intake

Intake done wrong creates messy data and weak consent records. ClinikAPI's components do it right by default.

What you get:

  • IntakeForm — a questionnaire that stores structured FHIR answers.
  • ConsentManager — consent signing and management as FHIR Consent records.
  • The proxy pattern — your secret key stays server-side.
  • FHIR underneath — intake and consent are part of the connected record.
  • Compliance included — HIPAA-compliant, SOC 2-audited, with a signed BAA.

See them in the UI Library, and read about consent and intake forms done right.

Frequently Asked Questions

1. How do I build a patient intake form in React?

Use ClinikAPI's IntakeForm component — it renders the questionnaire and stores answers as structured FHIR. Add it with a proxyUrl and patientId; no fields or validation to write.

2. What does IntakeForm do?

It presents an intake questionnaire and saves responses as structured FHIR answers, so the data is searchable and connected to the patient's record.

3. How do I collect consent?

Use ConsentManager — it handles consent signing and management, including scope, verification, and provisions, stored as a FHIR Consent record.

4. Is intake data stored as FHIR?

Yes — structured FHIR, so it's part of the patient's record from the start.

5. Can I theme the form?

Yes — a theme prop (like light or dark) makes it match your app.

Conclusion

Patient intake is two jobs — structured data and real consent — and both are easy to get wrong if you treat them as "just a form." With IntakeForm and ConsentManager, you collect intake answers as structured FHIR and capture consent as a verifiable record, with no fields, validation, or mapping to build. Place two components, provide a patient ID, and your intake is clean, connected, and compliant from day one.

Key takeaways:

  • Intake is two jobs: structured clinical data and legal consent.
  • IntakeForm stores answers as structured FHIR, not loose text.
  • ConsentManager stores consent as a real FHIR Consent record.
  • The proxy pattern keeps your secret key server-side.
  • You skip building fields, validation, mapping, and the consent flow.

Ready to build? Explore the UI Library or get your free API keys.

Related Articles

Share

Keep reading