Skip to main content
Forme supports native AcroForm components for creating interactive fillable PDF forms. Form fields work in every major PDF viewer without JavaScript or external form handling. Users fill in fields directly in their PDF viewer, and you can flatten forms at render time to lock in values as static content.
import {
  Document, Page, View, Text,
  TextField, Checkbox, Dropdown, RadioButton,
} from '@formepdf/react';

TextField

A single-line or multiline text input field.

Props

PropTypeDefaultDescription
namestring(required)Unique field name. Used as the PDF field identifier.
valuestring""Pre-filled text value.
placeholderstring-Placeholder text shown when the field is empty.
widthnumber(required)Field width in points.
heightnumber24Field height in points.
multilinebooleanfalseAllow multiple lines of text.
passwordbooleanfalseMask input with dots.
readOnlybooleanfalsePrevent editing. Useful for pre-filled fields that should not be changed.
maxLengthnumber-Maximum number of characters allowed.
fontSizenumber12Font size in points.
styleStyle-Additional style properties (margin, padding, etc.).

Example

<View style={{ gap: 12 }}>
  <Text style={{ fontSize: 10, fontWeight: 700 }}>Full Name</Text>
  <TextField name="fullName" value="Jane Smith" width={300} height={24} fontSize={10} />

  <Text style={{ fontSize: 10, fontWeight: 700 }}>Notes</Text>
  <TextField name="notes" multiline width={300} height={80} fontSize={10} />
</View>

Checkbox

A checkbox with checked or unchecked state.

Props

PropTypeDefaultDescription
namestring(required)Unique field name.
checkedbooleanfalseWhether the checkbox is checked by default.
widthnumber14Display width in points.
heightnumber14Display height in points.
readOnlybooleanfalsePrevent editing.
styleStyle-Additional style properties (margin, etc.).

Example

<View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
  <Checkbox name="agreeToTerms" />
  <Text style={{ fontSize: 10 }}>I agree to the terms and conditions</Text>
</View>

A select dropdown with predefined options.

Props

PropTypeDefaultDescription
namestring(required)Unique field name.
optionsstring[](required)List of selectable options.
valuestring-Pre-selected option. Must match one of the options values.
widthnumber(required)Field width in points.
heightnumber24Field height in points.
readOnlybooleanfalsePrevent editing.
fontSizenumber12Font size in points.
styleStyle-Additional style properties (margin, etc.).

Example

<View style={{ gap: 4 }}>
  <Text style={{ fontSize: 10, fontWeight: 700 }}>Country</Text>
  <Dropdown
    name="country"
    options={['United States', 'Canada', 'United Kingdom', 'Germany', 'France']}
    value="United States"
    width={200}
    height={24}
    fontSize={10}
  />
</View>

RadioButton

A radio button. Group multiple radio buttons by giving them the same name. Only one in the group can be selected at a time.

Props

PropTypeDefaultDescription
namestring(required)Group name. All radio buttons with the same name form a mutually exclusive group.
valuestring(required)The value this radio button represents within the group.
checkedbooleanfalseWhether this radio button is selected by default. Only one per group should be true.
widthnumber14Display width in points.
heightnumber14Display height in points.
readOnlybooleanfalsePrevent editing.
styleStyle-Additional style properties (margin, etc.).

Example

<View style={{ gap: 8 }}>
  <Text style={{ fontSize: 10, fontWeight: 700 }}>Payment Method</Text>

  <View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
    <RadioButton name="paymentMethod" value="creditCard" checked width={14} height={14} />
    <Text style={{ fontSize: 10 }}>Credit Card</Text>
  </View>

  <View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
    <RadioButton name="paymentMethod" value="bankTransfer" width={14} height={14} />
    <Text style={{ fontSize: 10 }}>Bank Transfer</Text>
  </View>

  <View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
    <RadioButton name="paymentMethod" value="check" width={14} height={14} />
    <Text style={{ fontSize: 10 }}>Check</Text>
  </View>
</View>
All three radio buttons share name="paymentMethod", so selecting one deselects the others.

Full Example: Contact Form

import {
  Document, Page, View, Text,
  TextField, Checkbox, Dropdown, RadioButton,
} from '@formepdf/react';

const ContactForm = () => (
  <Document title="Contact Form">
    <Page size="Letter" margin={54}>
      <Text style={{ fontSize: 20, fontWeight: 700, marginBottom: 16 }}>Contact Form</Text>

      <View style={{ gap: 12 }}>
        <View>
          <Text style={{ fontSize: 10, fontWeight: 700, marginBottom: 4 }}>Name</Text>
          <TextField name="name" placeholder="Your full name" width={300} fontSize={10} />
        </View>

        <View>
          <Text style={{ fontSize: 10, fontWeight: 700, marginBottom: 4 }}>Email</Text>
          <TextField name="email" placeholder="you@example.com" width={300} fontSize={10} />
        </View>

        <View>
          <Text style={{ fontSize: 10, fontWeight: 700, marginBottom: 4 }}>Department</Text>
          <Dropdown
            name="department"
            options={['Sales', 'Support', 'Engineering', 'Other']}
            width={200}
            fontSize={10}
          />
        </View>

        <View>
          <Text style={{ fontSize: 10, fontWeight: 700, marginBottom: 4 }}>Priority</Text>
          <View style={{ flexDirection: 'row', gap: 16 }}>
            <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
              <RadioButton name="priority" value="low" />
              <Text style={{ fontSize: 10 }}>Low</Text>
            </View>
            <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
              <RadioButton name="priority" value="medium" checked />
              <Text style={{ fontSize: 10 }}>Medium</Text>
            </View>
            <View style={{ flexDirection: 'row', alignItems: 'center', gap: 6 }}>
              <RadioButton name="priority" value="high" />
              <Text style={{ fontSize: 10 }}>High</Text>
            </View>
          </View>
        </View>

        <View>
          <Text style={{ fontSize: 10, fontWeight: 700, marginBottom: 4 }}>Message</Text>
          <TextField name="message" multiline width={400} height={100} fontSize={10} />
        </View>

        <View style={{ flexDirection: 'row', alignItems: 'center', gap: 8, marginTop: 8 }}>
          <Checkbox name="subscribe" checked />
          <Text style={{ fontSize: 10 }}>Subscribe to updates</Text>
        </View>
      </View>
    </Page>
  </Document>
);

Form Flattening

Flattening converts interactive form fields into static PDF content. The visual appearance is preserved, but users can no longer edit the fields. This is useful when you pre-fill a form with data and want to send a finalized, non-editable PDF.

At render time

Pass flattenForms: true to the render options:
import { renderDocument } from '@formepdf/core';

const pdfBytes = await renderDocument(
  <Document>
    <Page size="Letter" margin={54}>
      <TextField name="clientName" value="Jane Smith" readOnly width={200} height={24} fontSize={10} />
    </Page>
  </Document>,
  { flattenForms: true }
);

Via the hosted API

Pass flattenForms=true as a query parameter on any render endpoint:
curl https://api.formepdf.com/v1/render/intake-form?flattenForms=true \
  -H "Authorization: Bearer forme_sk_abc123..." \
  -H "Content-Type: application/json" \
  -d '{"clientName": "Jane Smith", "date": "2026-03-15"}'
See the Hosted API reference for details.

Edge cases

  • Flattening a form that has no fields produces an unchanged PDF.
  • Fields with no value flatten to empty space (the field widget is removed).
  • Read-only fields and editable fields are both flattened. The readOnly prop has no effect on the flattened output.

Known Limitations

  • Helvetica only for form field text. PDF form fields use the built-in Helvetica font regardless of the document’s font settings. This means form field text is limited to Latin characters. Document text outside of form fields uses your custom fonts as expected.
  • Field name collisions. If two fields share the same name (and are not radio buttons in the same group), they will be linked — editing one updates the other. Use unique names for independent fields.
  • macOS Preview quirks. macOS Preview renders basic text fields and checkboxes correctly, but dropdowns and radio buttons may not behave as expected. Use Chrome’s built-in PDF viewer or Adobe Acrobat for full form interactivity.

Viewer Compatibility

FeatureChromeAcrobatmacOS PreviewiOSAndroid
Text fieldsYesYesYesVariesVaries
CheckboxesYesYesYesVariesVaries
DropdownsYesYesLimitedVariesVaries
Radio buttonsYesYesLimitedVariesVaries
For the most reliable cross-platform experience, recommend Chrome or Adobe Acrobat to your users. If you need guaranteed rendering on all viewers, flatten the form before sending.