---
title: "Fill PDF form fields in C#"
url: https://recursiveai.org/onepdf/articles/fill-pdf-form-csharp/
description: "Fill PDF form fields in C# with OnePDF: read field names, set text, check boxes, radio buttons and lists, catch bad values, then flatten. MIT or Apache-2.0."
date: 2026-10-26
author: OnePDF team
---

# Fill PDF form fields in C#

Fill PDF form fields in C# with OnePDF: read field names, set text, check boxes, radio buttons and lists, catch bad values, then flatten. MIT or Apache-2.0.

October 26, 2026 · OnePDF team

To fill PDF form fields in C#, open the form with `AllowEditing`, call `SetValue` or `SetChecked` on `doc.Form` with each field’s name, and save. OnePDF checks each value against the field (its type, its options, its maximum length) and refuses one that doesn’t fit, then draws the new value into the field’s appearance so it shows in any viewer. It is pure C# with no native binaries, licensed MIT OR Apache-2.0. This page reads a form’s field names, fills every kind of field, fills from your own data while collecting bad values, and ends with flattening. Every sample was compiled and run against OnePDF 1.11.0 on .NET 10.

## Before you start

*Terminal · NuGet*

```
dotnet new console -o PdfForms
cd PdfForms
dotnet add package RecursiveAI.OnePdf --version 1.11.0
```

OnePDF targets .NET 10 (`net10.0`). The samples fill [OPM’s SF 2823](https://www.opm.gov/forms/pdf_fill/sf2823.pdf), the life-insurance beneficiary form for US federal employees. It has text fields, check boxes, two radio groups, a combo box, signature fields and buttons, so every case below runs on one real file. Save it as `sf2823.pdf` next to the program. The names and numbers filled in are made up.

## Read the form fields

Start by listing the fields: you need their exact names, and for buttons and lists, the values they accept.

*Program.cs · OnePDF 1.11.0 · .NET 10*

```
using OnePdf;
 
using PdfDocument doc = PdfDocument.Open("sf2823.pdf");
PdfAcroForm form = doc.Form ?? throw new InvalidOperationException("The file has no form.");
Console.WriteLine($"{form.TerminalFields.Count()} fields, XFA: {form.HasXfa}");
 
foreach (PdfFormField field in form.TerminalFields)
{
    // The values a field accepts: options for combo and list boxes, on-states for check boxes and radio buttons.
    IEnumerable<string> accepts = field.Kind switch
    {
        PdfFieldKind.ComboBox or PdfFieldKind.ListBox => field.Options.Select(o => o.Export),
        PdfFieldKind.CheckBox or PdfFieldKind.RadioButton => field.Widgets
            .SelectMany(w => w.GetDictionary("AP")?.GetDictionary("N")?.Keys ?? [])
            .Where(state => state != "Off")
            .Distinct(),
        _ => [],
    };
    string max = field.MaxLength is int n ? $" (max {n})" : "";
    Console.WriteLine($"{field.FullName,-22} {field.Kind,-12} {string.Join(" | ", accepts)}{max}");
}
```

*Output · Excerpt*

```
61 fields, XFA: False
Bene 1.0               Text
not assigned           CheckBox     Yes
Clear                  PushButton
Print copies           ComboBox     Part 1 - Original | Part 2 - Duplicate
Witness Signature 1    Signature
Name                   Text
DOB                    Text
SSN                    Text          (max 11)
Type of Insured        RadioButton  Employee | Retiree | Compensationer
I Am                   RadioButton  Insured | Assignee
```

- `TerminalFields` lists the fields that hold values. Names are fully qualified (`parent.child`): `Bene 1.0` is the child `0` of a field named `Bene 1`.
- A check box or radio button has a name for each “on” state, stored as a key of its widgets’ normal appearance (`/AP /N`). That is the value to set: here `Yes` for the check boxes and `Employee`, `Retiree` or `Compensationer` for the radio group. Don’t guess `true` or `1`.
- `HasXfa` tells you whether the file also carries an XFA form. OnePDF fills AcroForm fields, so an XFA-only form can’t be filled.
- The same loop reads a filled form: `field.Value` is the current value, and `field.Values` gives every selection of a multi-select list.

## Fill text fields, check boxes, radio buttons and lists

*Program.cs · OnePDF 1.11.0 · .NET 10*

```
using OnePdf;
 
using (PdfDocument doc = PdfDocument.Open("sf2823.pdf", new PdfOpenOptions { AllowEditing = true }))
{
    PdfAcroForm form = doc.Form!;
 
    form.SetValue("Name", "Lovelace, Ada");                 // text
    form.SetValue("DOB", "12/10/1985");
    form.SetValue("SSN", "123-45-6789");
    form.SetValue("Type of Insured", "Employee");           // radio group: one of its on-states
    form.SetValue("Bene 1.0", "Byron King");
    form.SetValue("Relationship 1.0", "Son");
    form.SetValue("amount 1.0", "100%");
    form.SetValue("Total", "100%");
    form.SetValue("I Am", "Insured");
    form.SetChecked("not assigned", true);                  // check box
    form.SetChecked("witnessed", true);
    form.SetChecked("no beneficiary", true);
    form.SetValue("Print copies", "Part 2 - Duplicate");    // combo box: export value or display text
 
    doc.Save("filled.pdf");                                 // still a fillable form
}
 
// Read the values back.
using (PdfDocument filled = PdfDocument.Open("filled.pdf"))
{
    foreach (string name in new[] { "Name", "Type of Insured", "not assigned", "Print copies" })
        Console.WriteLine($"{name} = {filled.Form!.FindField(name)!.Value}");
}
```

*Output · Console*

```
Name = Lovelace, Ada
Type of Insured = Employee
not assigned = Yes
Print copies = Part 2 - Duplicate
```

The page above is `filled.pdf` as a viewer draws it. OnePDF built and stored each field’s appearance, so the values show without the viewer redrawing the fields, and the file is still a form anyone can edit. To add the changes after the original bytes instead of rewriting the file, save with `doc.SaveIncremental(stream)`.

### What each kind of field accepts

| Field kind | Call | Value |
|---|---|---|
| Text | `SetValue(name, text)` | Any text up to the field’s maximum length. `null` clears it. Comb, multi-line and password fields are drawn from the field’s flags. |
| Check box | `SetChecked(name, true)` or `SetValue(name, state)` | An on-state such as `Yes`, or `Off`. `SetChecked(true)` picks the first widget’s on-state. |
| Radio group | `SetValue(name, state)` | One of the group’s on-states. `Off` or `SetChecked(name, false)` clears the group. |
| Combo box, list box | `SetValue(name, choice)` | An option’s export value or display text. An editable combo box takes any text. |
| Multi-select list box | `SetValues(name, choices)` | Several options, stored in option order. |
| Push button, signature | None | Refused with `WrongType`. Signing is [its own operation](https://recursiveai.org/onepdf/cookbook/sign-and-verify/). |

The same calls exist on each field: `form.FindField(name)?.SetValue(...)`. `Reset` and `ResetAll` return fields to their defaults.

## Fill a form from your data and catch bad values

In a real program the values come from a database row or a request, and some won’t fit the form. Each call that can’t store its value throws `PdfFormValueException` and changes nothing, so you can collect the problems and decide what to do:

*Program.cs · OnePDF 1.11.0 · .NET 10*

```
using OnePdf;
 
// Values from your own data: a database row, a request body, a CSV line.
var values = new Dictionary<string, string>
{
    ["Name"] = "Hopper, Grace",
    ["DOB"] = "12/09/1986",
    ["SSN"] = "123-45-67890",            // 12 characters: the field allows 11
    ["Type of Insured"] = "Contractor",  // not one of the radio group's states
    ["not assigned"] = "Yes",            // a check box's on-state
    ["Middle name"] = "Brewster",        // no such field
};
 
using PdfDocument doc = PdfDocument.Open("sf2823.pdf", new PdfOpenOptions { AllowEditing = true });
PdfAcroForm form = doc.Form!;
 
var problems = new List<string>();
foreach ((string name, string value) in values)
{
    try
    {
        form.SetValue(name, value);
    }
    catch (PdfFormValueException e)
    {
        problems.Add($"{name}: {e.Reason}");   // the refused call changed nothing
    }
}
 
if (problems.Count > 0)
    Console.WriteLine(string.Join(Environment.NewLine, problems));
doc.Save("filled-from-data.pdf");
```

*Output · Console*

```
SSN: TooLong
Type of Insured: NotInOptions
Middle name: UnknownField
```

The name, date of birth and check box were stored. The other three were refused, each for its own reason:

| `Reason` | When |
|---|---|
| `UnknownField` | No field has that fully qualified name. |
| `WrongType` | The call doesn’t fit the field, such as a value for a push button or a signature. |
| `ReadOnly` | The field is read-only. `PdfFillOptions.OverrideReadOnly` fills it anyway. |
| `NotInOptions` | The value isn’t one of a list’s options or a button’s on-states. |
| `TooLong` | The text is longer than the field’s maximum length. `PdfFillOptions.TruncateToMaxLength` cuts it instead. |
| `NotMultiSelect` | Several values for a field that isn’t a multi-select list box. |
| `NotTerminal` | The name is a parent field. Fill its children. |

## Keep the form fillable or flatten it

A filled form stays editable: anyone can change the values in a viewer. To make them permanent, flatten the document after filling, with `doc.Flatten()` before `Save`. The values become page content and the fields are removed. Flattening, partial flattening and leaving out the Print and Clear buttons are covered in [flatten a PDF form in C#](https://recursiveai.org/onepdf/articles/flatten-pdf-csharp/). To fill one copy per record and combine them into one file, see [merge PDF files in C#](https://recursiveai.org/onepdf/articles/merge-pdf-csharp/), which also shows how OnePDF keeps two filled copies of the same form apart.

## What OnePDF doesn’t do when filling

- **Scripts never run.** Calculate, format, validate and keystroke scripts are left as data. A total field isn’t recomputed and a date isn’t reformatted: values are stored exactly as you give them, so format them yourself.
- **XFA data isn’t filled.** Forms that are XFA only can’t be filled. On forms that carry both, OnePDF fills the AcroForm fields, and flattening removes the XFA along with the form.
- **No new fields.** OnePDF fills the fields a form has. It doesn’t add fields to a PDF.

Every rule for each field type is in [forms](https://recursiveai.org/onepdf/docs/forms/), and how appearances are drawn is in [appearance generation](https://recursiveai.org/onepdf/docs/appearance-generation/).

## The same with iText

iText fills fields through [`PdfAcroForm`](https://api.itextpdf.com/iText/dotnet/9.8.0/classi_text_1_1_forms_1_1_pdf_acro_form.html): `GetField(name)` returns the field and `SetValue` sets it. iText’s knowledge base makes the same point about check boxes: “You shouldn’t ‘guess’ for the possible values. You need to use a value that is stored in the PDF” ([how to check a check box](https://kb.itextpdf.com/itext/how-to-check-a-check-box)). Written from those pages and run with iText 9.8.0 (AGPL or commercial):

*Program.cs · iText 9.8.0*

```
using iText.Forms;
using iText.Kernel.Pdf;
 
using PdfDocument pdf = new PdfDocument(new PdfReader("sf2823.pdf"), new PdfWriter("filled-itext.pdf"));
PdfAcroForm form = PdfAcroForm.GetAcroForm(pdf, true);
 
form.GetField("Name").SetValue("Lovelace, Ada");
form.GetField("Type of Insured").SetValue("Employee");
form.GetField("not assigned").SetValue("Yes");
form.GetField("Print copies").SetValue("Part 2 - Duplicate");
```

It fills the same four fields. The file’s producer then ends with “modified using iText® Core 9.8.0 (AGPL version)”, which the AGPL edition requires: see [iText license cost and AGPL terms](https://recursiveai.org/onepdf/articles/itext-license/). PDFsharp’s [FAQ](https://docs.pdfsharp.net/PDFsharp/Overview/FAQ.html) describes its AcroForm support as limited.

## Where next

- [Fill and flatten form fields](https://recursiveai.org/onepdf/cookbook/fill-flatten-forms/), the cookbook recipe.
- [Flatten a PDF form in C#](https://recursiveai.org/onepdf/articles/flatten-pdf-csharp/) once the values are in.
- [Extract text from a PDF in C#](https://recursiveai.org/onepdf/articles/extract-text-from-pdf-csharp/) to read values from forms that were flattened or printed.
- [Getting started with OnePDF](https://recursiveai.org/onepdf/docs/getting-started/).
