Fill PDF form fields in C#
Load the PDF with PdfFormManager, look up each field by name in Fields, set its value and save. The sample first makes the fillable form itself, by converting an HTML form with CreateFormFields turned on.
Compiled and run: Linux ARM64 · Linux x64 · macOS ARM64 · Windows x64
Build it step by step.
-
1Install the NuGet packages
SelectPdf.Universalis the library. The native package carries the Chromium engine for one platform: add the one for the platform you run on.dotnet add package SelectPdf.Universal dotnet add package SelectPdf.Universal.Native.win-x64
dotnet add package SelectPdf.Universal dotnet add package SelectPdf.Universal.Native.linux-x64
dotnet add package SelectPdf.Universal dotnet add package SelectPdf.Universal.Native.linux-arm64
dotnet add package SelectPdf.Universal dotnet add package SelectPdf.Universal.Native.osx-arm64
-
2Create a console app
Any .NET 8 or .NET 10 project works. To follow along, create a console app, run the install commands above inside its folder, then replace
Program.cswith the code below.dotnet new console -n PdfSample cd PdfSample
-
3Write the HTML form
// an HTML form: every control has a name string html = """ <style>body { font-family: Arial, sans-serif; }</style> <h1>Conference registration</h1> <form> <p><label>Full name <input type="text" name="fullName"></label></p> <p><label>Email <input type="email" name="email"></label></p> <p><label>Ticket <select name="ticket"> <option value="standard">Standard</option> <option value="workshop">Workshop</option> <option value="vip">VIP</option> </select></label></p> <p>Meal: <label><input type="radio" name="meal" value="regular"> Regular</label> <label><input type="radio" name="meal" value="vegetarian"> Vegetarian</label></p> <p><label><input type="checkbox" name="newsletter"> Send me the newsletter</label></p> </form> """;Give every control a
name: it becomes the name of the PDF field. In your application the form is usually a page or a template you already have, or you start from an existing fillable PDF and skip the conversion. -
4Convert it into a fillable PDF form
// convert it into a fillable PDF form HtmlToPdf converter = new HtmlToPdf(); converter.Options.CreateFormFields = true; PdfDocument doc = converter.ConvertHtmlString(html); doc.Save("registration-form.pdf"); doc.Close();Options.CreateFormFields = trueturns the controls into PDF form fields instead of printing them as they look on the page. The text boxes, the select, the radio buttons and the check box keep the page's own look. -
5Load the form and fill the fields by name
// load the form and fill the fields by name PdfFormManager form = new PdfFormManager(); form.Load("registration-form.pdf"); ((PdfFormFieldTextBox)form.Fields["fullName"]).Text = "Jane Doe"; ((PdfFormFieldTextBox)form.Fields["email"]).Text = "jane.doe@example.com"; ((PdfFormFieldComboBox)form.Fields["ticket"]).SelectedValue = "workshop"; ((PdfFormFieldRadioButtonList)form.Fields["meal"]).SelectedValue = "vegetarian"; ((PdfFormFieldCheckBox)form.Fields["newsletter"]).Checked = true;PdfFormManager.Loadopens the PDF, andFields["name"]returns the field with that name. Cast it to its type to set the value:Textfor a text box,SelectedValuefor a combo box or a radio button list,Checkedfor a check box. -
6Save the filled form
// save the filled form form.Save("registration-filled.pdf"); form.Close();Savewritesregistration-filled.pdfwith the values in the fields, which stay editable in a PDF viewer.Closereleases the document. -
7Run it
dotnet run
The program writes
registration-filled.pdfto the working folder. Without a license key, every page carries a trial watermark; setGlobalProperties.LicenseKeybefore the first conversion to remove it.
The complete Program.cs.
This is the exact file our samples pipeline compiled and ran on Linux ARM64 and Linux x64 and macOS ARM64 and Windows x64 to produce the output on this page.
using SelectPdf.Universal;
// an HTML form: every control has a name
string html = """
<style>body { font-family: Arial, sans-serif; }</style>
<h1>Conference registration</h1>
<form>
<p><label>Full name <input type="text" name="fullName"></label></p>
<p><label>Email <input type="email" name="email"></label></p>
<p><label>Ticket
<select name="ticket">
<option value="standard">Standard</option>
<option value="workshop">Workshop</option>
<option value="vip">VIP</option>
</select></label></p>
<p>Meal:
<label><input type="radio" name="meal" value="regular"> Regular</label>
<label><input type="radio" name="meal" value="vegetarian"> Vegetarian</label></p>
<p><label><input type="checkbox" name="newsletter"> Send me the newsletter</label></p>
</form>
""";
// convert it into a fillable PDF form
HtmlToPdf converter = new HtmlToPdf();
converter.Options.CreateFormFields = true;
PdfDocument doc = converter.ConvertHtmlString(html);
doc.Save("registration-form.pdf");
doc.Close();
// load the form and fill the fields by name
PdfFormManager form = new PdfFormManager();
form.Load("registration-form.pdf");
((PdfFormFieldTextBox)form.Fields["fullName"]).Text = "Jane Doe";
((PdfFormFieldTextBox)form.Fields["email"]).Text = "jane.doe@example.com";
((PdfFormFieldComboBox)form.Fields["ticket"]).SelectedValue = "workshop";
((PdfFormFieldRadioButtonList)form.Fields["meal"]).SelectedValue = "vegetarian";
((PdfFormFieldCheckBox)form.Fields["newsletter"]).Checked = true;
// save the filled form
form.Save("registration-filled.pdf");
form.Close();
Open the project on GitHub → this program and the variations below, ready to dotnet run
The PDF it produces.
Download registration-filled.pdf ↓ the file this sample produced, unedited
Variations you will need next.
Each variation is a separate file in the same project, compiled and run with the program above.
List the fields of a form with their types and values
Before filling a form you did not create, find out what it contains. Enumerating Fields gives every field; its class (PdfFormFieldTextBox, PdfFormFieldCheckBox, PdfFormFieldRadioButtonList, PdfFormFieldComboBox or PdfFormFieldListBox) tells you which property holds its value. Load also accepts a PdfDocument, so a converted document is read without saving it first.
using SelectPdf.Universal;
static class ListFormFields
{
public static void Run()
{
// a form that already holds values (made here so the sample runs on its own)
HtmlToPdf converter = new HtmlToPdf();
converter.Options.CreateFormFields = true;
PdfDocument doc = converter.ConvertHtmlString("""
<form>
<input type="text" name="company" value="Contoso Ltd">
<textarea name="notes">Deliver to the side entrance.</textarea>
<input type="checkbox" name="express" checked>
<input type="radio" name="payment" value="card">
<input type="radio" name="payment" value="invoice" checked>
<select name="country"><option>France</option><option selected>Germany</option></select>
<select name="extras" multiple>
<option selected>Gift wrap</option><option>Insurance</option><option selected>Tracking</option>
</select>
</form>
""");
// list every field: name, type and current value
PdfFormManager form = new PdfFormManager();
form.Load(doc);
List<string> lines = new List<string>();
foreach (PdfFormField field in form.Fields)
{
string value = field switch
{
PdfFormFieldTextBox text => text.Text,
PdfFormFieldCheckBox check => check.Checked.ToString(),
PdfFormFieldRadioButtonList radio => radio.SelectedValue,
PdfFormFieldComboBox combo => combo.SelectedValue,
PdfFormFieldListBox list => string.Join(", ", list.SelectedValues),
_ => ""
};
lines.Add($"{field.Name} ({field.GetType().Name}, page {field.DisplayPage}): {value}");
}
form.Close();
doc.Close();
File.WriteAllLines("form-fields.txt", lines);
lines.ForEach(Console.WriteLine);
}
}
Fill a form in memory and make it read-only
Load takes a byte array (or a stream), so a form from a database or an upload never touches the disk. Setting ReadOnly on the PdfFormManager marks every field read-only; set ReadOnly on a single field to lock only that one. To turn the fields into ordinary page content instead, see the guide on flattening a PDF form.
using SelectPdf.Universal;
static class FillAndLock
{
public static void Run()
{
// a blank form (made here so the sample runs on its own)
HtmlToPdf converter = new HtmlToPdf();
converter.Options.CreateFormFields = true;
PdfDocument doc = converter.ConvertHtmlString("""
<h1>Leave request</h1>
<p><label>Employee <input type="text" name="employee"></label></p>
<p><label>From <input type="text" name="from"></label>
<label>To <input type="text" name="to"></label></p>
<p><label><input type="checkbox" name="approved"> Approved</label></p>
""");
byte[] blank = doc.Save();
doc.Close();
// fill the form from memory, then make every field read-only
PdfFormManager form = new PdfFormManager();
form.Load(blank);
((PdfFormFieldTextBox)form.Fields["employee"]).Text = "Jane Doe";
((PdfFormFieldTextBox)form.Fields["from"]).Text = "2026-11-02";
((PdfFormFieldTextBox)form.Fields["to"]).Text = "2026-11-06";
((PdfFormFieldCheckBox)form.Fields["approved"]).Checked = true;
form.ReadOnly = true;
form.Save("leave-request-locked.pdf");
form.Close();
}
}
Fill a form from JSON values
When the values arrive as data keyed by field name, walk the fields and set each one from the value with its name. A switch on the field's type picks the property to set, so the same loop fills any form whose field names match the keys.
using System.Text.Json;
using SelectPdf.Universal;
static class FillFromJson
{
public static void Run()
{
// a blank form (made here so the sample runs on its own)
HtmlToPdf converter = new HtmlToPdf();
converter.Options.CreateFormFields = true;
PdfDocument doc = converter.ConvertHtmlString("""
<h1>Shipping label</h1>
<p><label>Recipient <input type="text" name="recipient"></label></p>
<p><label>City <input type="text" name="city"></label></p>
<p><label>Service <select name="service">
<option value="standard">Standard</option><option value="express">Express</option>
</select></label></p>
<p><label><input type="checkbox" name="fragile"> Fragile</label></p>
""");
doc.Save("shipping-label-form.pdf");
doc.Close();
// the values, keyed by field name, as they arrive from an API or a database
string json = """
{ "recipient": "Contoso Ltd", "city": "Berlin", "service": "express", "fragile": "true" }
""";
Dictionary<string, string> values = JsonSerializer.Deserialize<Dictionary<string, string>>(json)!;
// set each field from the value with its name
PdfFormManager form = new PdfFormManager();
form.Load("shipping-label-form.pdf");
foreach (PdfFormField field in form.Fields)
{
if (!values.TryGetValue(field.Name, out string? value)) continue;
switch (field)
{
case PdfFormFieldTextBox text: text.Text = value; break;
case PdfFormFieldCheckBox check: check.Checked = bool.Parse(value); break;
case PdfFormFieldComboBox combo: combo.SelectedValue = value; break;
case PdfFormFieldRadioButtonList radio: radio.SelectedValue = value; break;
}
}
form.Save("shipping-label-filled.pdf");
form.Close();
}
}
Common problems and fixes.
A field cannot be found by its name
A converted field is named after the control's name, or its id when it has none, and a name used twice gets a suffix. For a form you did not create, list the fields to see their exact names. A nested field is looked up by its fully-qualified name, such as address.city, which FullName returns.
The PDF has no fields after the conversion
Set Options.CreateFormFields = true before converting, and keep Options.JavaScriptEnabled on: the controls are read by a script after the page's own scripts have run. Hidden, file, image and button inputs never become fields.
A combo box or radio button value is not selected
SelectedValue takes one of the values the field offers, which Items returns. For a converted form these are the value attributes of the options and radio buttons. SelectedIndex selects by position instead.
The filled form is signed, or larger than expected
Save appends the changes to the original document, which keeps an earlier signature verifiable. Set CompactSave = true to write a new, smaller document instead, knowing that a signature the document carried no longer verifies.
The PDF form is password-protected
Use the Load overload that takes a password, for a file, a stream, a byte array or a PdfDocument.
Good to know.
- With CreateFormFields set to true, text, email, number, date and similar inputs, check boxes, radio buttons, selects and text areas become fillable PDF form fields placed over the controls as they were printed. The default is false. Source
- Each converted field takes the name of its HTML control, or its id when it has no name, along with the control's current value and its read-only, required and maximum length settings. Source
- PdfFormManager reads and fills text boxes, check boxes, list boxes, combo boxes and radio button lists in existing PDF documents that contain AcroForm fields. Source
- By default PdfFormManager saves an incremental update: the loaded document is written unchanged and the changes are appended, which keeps a signature made before the form was filled verifiable. Source
- Hidden, file, image and button inputs are not converted into fields, and a password input's value is not carried into the PDF. Source
Questions, answered.
Short answers about this guide. The SelectPdf.Universal documentation covers every class and option.