# Form Fields

> Create fillable forms with ServerTextControl: text, check box, selection and date fields, formats that keep them, filled values, radio buttons and flattening.

- **Product:** TX Text Control .NET Server
- **Section:** Documentation
- **Kind:** Topic
- **Path:** TX Text Control .NET Server > Document Processing > Form Fields
- **5073 words**
- **Web URL:** https://docs.textcontrol.com/tx-text-control-dotnet-server/document-processing/form-fields/
- **LLMs URL:** https://docs.textcontrol.com/tx-text-control-dotnet-server/document-processing/form-fields/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/tx-text-control-dotnet-server/document-processing/form-fields/llms-full.txt

---

An order form, an insurance claim or a checklist becomes fillable when its blanks are form fields: text boxes, check boxes, drop-down lists and date pickers that users fill out in the Document Editor, the Document Viewer, MS Word or a PDF reader. On the server, your code creates such forms, reads and checks the values users entered and replaces the fields with their values before the document is archived or sent.

MS Word forms with content controls are covered in [Content Controls](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-processing/content-controls/llms-full.txt), which reads and fills DOCX forms. Filling form fields from data with `MailMerge` is part of [Merge Fields](https://docs.textcontrol.com/tx-text-control-dotnet-server/mail-merge/fields/#merge-form-fields). The examples below are console programs for *Program.cs*.

### Form Field Types

All form fields derive from [FormField](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/formfield/llms-full.txt), which in turn derives from `TextField`, and are managed in the [FormFieldCollection](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/formfieldcollection/llms-full.txt) of [ServerTextControl.FormFields](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/servertextcontrol/formfields-property/llms-full.txt). There are four types:

| Class | Form field | Value | Settings |
|---|---|---|---|
| [TextFormField](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/textformfield/llms-full.txt) | Text box | `Text` | [EmptyWidth](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/textformfield/emptywidth-property/llms-full.txt), the width in twips while the field is empty |
| [CheckFormField](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/checkformfield/llms-full.txt) | Check box | [Checked](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/checkformfield/checked-property/llms-full.txt) | [CheckedCharacter](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/checkformfield/checkedcharacter-property/llms-full.txt) and [UncheckedCharacter](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/checkformfield/uncheckedcharacter-property/llms-full.txt), the characters that show the checked and the unchecked state |
| [SelectionFormField](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/selectionformfield/llms-full.txt) | Drop-down list or combo box | [SelectedIndex](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/selectionformfield/selectedindex-property/llms-full.txt) and `Text` | [Items](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/selectionformfield/items-property/llms-full.txt), [IsDropDownArrowVisible](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/selectionformfield/isdropdownarrowvisible-property/llms-full.txt), `EmptyWidth` |
| [DateFormField](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/dateformfield/llms-full.txt) | Date picker | [Date](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/dateformfield/date-property/llms-full.txt), `null` when empty | [DateFormat](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/dateformfield/dateformat-property/llms-full.txt), [IsDateControlVisible](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/dateformfield/isdatecontrolvisible-property/llms-full.txt), `EmptyWidth` |

Every form field also has the properties of a text field, such as [Name](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/textfield/name-property/llms-full.txt) and [ID](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/textfield/id-property/llms-full.txt), which identify it, and [Deleteable](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/textfield/deleteable-property/llms-full.txt), which decides whether users can delete it. Two properties belong to form fields only:

- **[Enabled](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/formfield/enabled-property/llms-full.txt)** decides whether users can fill out the field in a protected form. It's `true` by default.
- **[DescriptiveText](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/formfield/descriptivetext-property/llms-full.txt)** describes the field for screen readers and in accessible PDF documents.

### Create a Fillable Form

A form field is inserted at the current input position. The following program writes a heading, adds a table with a label column and inserts one form field of each type into the second column. It saves the form in three formats:

```csharp
using TXTextControl;

using (ServerTextControl tx = new ServerTextControl())
{
    tx.Create();

    tx.Selection.Text = "Order Form\r\n\r\n";

    // A table with a label column and a column for the form fields
    tx.Tables.Add(4, 2, 10);
    Table table = tx.Tables.GetItem(10);

    table.Cells.GetItem(1, 1).Text = "Customer";
    table.Cells.GetItem(2, 1).Text = "Product";
    table.Cells.GetItem(3, 1).Text = "Invoice date";
    table.Cells.GetItem(4, 1).Text = "Terms accepted";

    // A text box that is 2 inches (2880 twips) wide while it's empty
    TextFormField customer = new TextFormField(2880)
    {
        Name = "Customer",
        ID = 1,
        Text = "Acme Corporation"
    };

    // A drop-down list with the first item selected
    SelectionFormField product = new SelectionFormField(
        new string[] { "TX Text Control .NET Server License", "Priority Support - 12 Months" }, 0)
    {
        Name = "Product",
        Editable = false
    };

    // A date picker with a date and the default width
    DateFormField invoiceDate = new DateFormField(new DateTime(2025, 5, 27), 0)
    {
        Name = "InvoiceDate"
    };

    // An unchecked check box
    CheckFormField termsAccepted = new CheckFormField(false)
    {
        Name = "TermsAccepted"
    };

    FormField[] fields = { customer, product, invoiceDate, termsAccepted };

    for (int row = 1; row <= fields.Length; row++)
    {
        // Selection positions start at 0, TableCell.Start at 1
        tx.Select(table.Cells.GetItem(row, 2).Start - 1, 0);

        if (!tx.FormFields.CanAdd || !tx.FormFields.Add(fields[row - 1]))
        {
            Console.WriteLine($"{fields[row - 1].Name} couldn't be added.");
        }
    }

    // A text for screen readers and accessible PDF documents
    customer.DescriptiveText = "Name of the customer";

    tx.Save("form.tx", StreamType.InternalUnicodeFormat);
    tx.Save("form.docx", StreamType.WordprocessingML);
    tx.Save("form.pdf", StreamType.AdobePDF);
}
```

The code works as follows:

- The [TextFormField constructor](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/textformfield/constructor/llms-full.txt) takes the width of the empty field in twips, 1/1440 inch; 0 selects a default width.
- The [SelectionFormField constructor](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/selectionformfield/constructor/llms-full.txt) takes the items and the zero-based index of the selected item, or -1 for no selection. An item can't be an empty string. [Editable](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/textfield/editable-property/llms-full.txt) set to `false` makes the field a drop-down list; with `true`, users can also type text, as in a combo box.
- The [DateFormField constructor](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/dateformfield/constructor/llms-full.txt) takes the date and the width of the empty field. The date is formatted with the culture of the text at the field's position.
- The [CheckFormField constructor](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/checkformfield/constructor/llms-full.txt) takes the checked state.
- [CanAdd](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/textfieldcollectionbase/canadd-property/llms-full.txt) is `false` where no field can be inserted, for example inside another field. [FormFieldCollection.Add](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/formfieldcollection/add-method/llms-full.txt) returns `true` if the field was inserted.

### Formats That Keep Form Fields

Which kind of form field a saved document contains depends on its format:

| Format | Form fields become |
|---|---|
| TX Text Control format (*.tx*) | TX Text Control form fields |
| DOCX | Content controls, which MS Word shows as form controls |
| RTF and DOC | Legacy form fields of MS Word; DOC is available with the Classic engine only |
| PDF | PDF form fields with their names and values, so the form can be filled out in a PDF reader |

When DOCX, DOC and RTF files are loaded, their content controls and legacy form fields become form fields again, unless `LoadSettings.ApplicationFieldFormat` is set to `MSWord`, as [Content Controls](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-processing/content-controls/#what-content-controls-are) explains. The values of PDF forms that come back filled out are read with [Forms.GetAcroFormFields](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol-documentserver-pdf/forms/getacroformfields-method/llms-full.txt), described in [PDF Forms](https://docs.textcontrol.com/tx-text-control-dotnet-server/pdf/forms/llms-full.txt).

### Read and Check the Values of a Filled Form

A form filled out in the Document Viewer can be saved with its values, as [Save the Filled Form](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-viewer/form-fields/#save-the-filled-form) describes, and sent to your server. The following program loads such a form, saved as *Documents/form-filled.tx*, collects the value of every form field in headers, footers and text frames too, prints the values as JSON and lists the fields that are empty:

```csharp
using System.Text.Json;
using TXTextControl;

Dictionary<string, object?> values = new Dictionary<string, object?>();
List<string> missing = new List<string>();

using (ServerTextControl tx = new ServerTextControl())
{
    tx.Create();
    tx.Load("Documents/form-filled.tx", StreamType.InternalUnicodeFormat);

    // The main text, text frames, headers and footers
    foreach (IFormattedText textPart in tx.TextParts)
    {
        foreach (FormField field in textPart.FormFields)
        {
            string name = string.IsNullOrEmpty(field.Name) ? $"Field {field.ID}" : field.Name;

            switch (field)
            {
                case CheckFormField checkBox:
                    values[name] = checkBox.Checked;
                    break;

                case DateFormField dateField:
                    values[name] = dateField.Date?.ToString("yyyy-MM-dd");
                    if (dateField.Date == null) missing.Add(name);
                    break;

                default:
                    // Text boxes and selection fields: the text the field shows
                    values[name] = field.Text;
                    if (string.IsNullOrEmpty(field.Text)) missing.Add(name);
                    break;
            }
        }
    }
}

Console.WriteLine(JsonSerializer.Serialize(values, new JsonSerializerOptions { WriteIndented = true }));

foreach (string name in missing)
{
    Console.WriteLine($"Missing value: {name}");
}
```

The code works as follows:

- [ServerTextControl.TextParts](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/servertextcontrol/textparts-property/llms-full.txt) contains the main text, the text frames and the headers and footers. Each of them has a [FormFields](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/iformattedtext/formfields-property/llms-full.txt) collection of its own; `ServerTextControl.FormFields` contains only the form fields of the main text.
- The `switch` statement reads the value that fits each type: `Checked` for check boxes, `Date` for date pickers and, for text boxes and selection form fields, `Text`, the text the field shows.

The Document Editor checks values while users fill out a form, with conditional instructions designed in its **Form Validation** group, as [Validate Form Fields](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-editor/form-fields/#validate-form-fields) describes, and the Document Viewer checks that the required fields are completed, as [Validate and Submit the Values](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-viewer/form-fields/#validate-and-submit-the-values) shows. Conditional instructions run only in the form protection mode, which needs an editor's `EditMode`, so code on the server checks the values it receives itself, as the program above does for empty fields.

### Conditional Instructions and Radio Button Groups

A conditional instruction is a rule stored in the document: when the values of form fields meet its conditions, it changes other fields, for example enables them, sets their values or marks them as invalid. Users create these rules in the Document Editor, and they run in the Document Editor and the Document Viewer. `ServerTextControl` keeps them when a form is saved in the TX Text Control format, but it can't read, add or apply them, as [Where Conditional Instructions Run](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-processing/conditional-instructions/#where-conditional-instructions-run) explains.

A radio button group, from which users choose exactly one option, is built from check box fields and conditional instructions. The server can create the check boxes with the look of radio buttons:

```csharp
using TXTextControl;

using (ServerTextControl tx = new ServerTextControl())
{
    tx.Create();

    tx.Selection.Text = "Shipping method:\r\n";

    string[] options = { "Standard", "Express" };

    foreach (string option in options)
    {
        CheckFormField radioButton = new CheckFormField(false)
        {
            Name = "Shipping" + option
        };

        tx.FormFields.Add(radioButton);

        // Radio button characters, set after the field was added
        radioButton.CheckedCharacter = '\x25c9';
        radioButton.UncheckedCharacter = '\x2b55';

        tx.Selection.Text = " " + option + "\r\n";
    }

    tx.Save("shipping-form.tx", StreamType.InternalUnicodeFormat);
}
```

`CheckedCharacter` and `UncheckedCharacter` are the characters that show the two states, here U+25C9 (a filled circle) and U+2B55 (an empty circle). Set them after `Add`: set before, in the object initializer, they are stored, but the field shows the default check box character.

The group behavior comes from two conditional instructions for each button, designed in the Document Editor: one unchecks the other buttons, and one keeps a checked button from being cleared. [Radio Button Groups](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-processing/conditional-instructions/#radio-button-groups) lists both rules.

### Flatten Form Fields

Before a filled form is archived or sent, you can replace its form fields with their values, so that nobody can change them. This is called flattening: for each text part, `textPart.GetTextFields(TextFieldType.FormFields).Clear(true)` removes the form fields and keeps their text. [Flatten Forms](https://docs.textcontrol.com/tx-text-control-dotnet-server/pdf/forms/flatten/llms-full.txt) shows the code for all fields, some fields and fields of one type, and flattening during a merge or before signing.

### Find Form Fields and React to Changes

- **By ID.** [FormFieldCollection.GetItem](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/formfieldcollection/getitem-method/llms-full.txt) with an ID returns the form field with that ID or `null`; without a parameter, it returns the form field at the input position.
- **By type.** [ServerTextControl.GetTextFields](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/servertextcontrol/gettextfields-method/llms-full.txt) with a value of [TextFieldType](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/textfieldtype/enumeration/llms-full.txt), such as `TextFieldType.CheckFormField` or `TextFieldType.FormFields` for all types, returns the fields of these types.
- **Events.** [TextFieldCreated](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/servertextcontrol/textfieldcreated-event/llms-full.txt) and [TextFieldDeleted](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol/servertextcontrol/textfielddeleted-event/llms-full.txt) occur for form fields as for all other fields, as [Events](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-processing/events/llms-full.txt) describes.

The blog article [Automatically Mapping TX Text Control Form Fields to JSON Data in .NET C#](https://www.textcontrol.com/blog/2026/06/03/automatically-mapping-tx-text-control-form-fields-to-json-data-in-dotnet-csharp/) renames form fields to match the property names of JSON data.

### Next Steps

- [Content Controls](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-processing/content-controls/llms-full.txt): read and fill MS Word forms.
- [Conditional Instructions](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-processing/conditional-instructions/llms-full.txt): the rules that validate and change form fields.
- [Merge Fields](https://docs.textcontrol.com/tx-text-control-dotnet-server/mail-merge/fields/#merge-form-fields): fill form fields with data in a mail merge.
- [Form Fields](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-viewer/form-fields/llms-full.txt) in the Document Viewer: let users fill out and submit a form.
- [Form Fields](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-editor/form-fields/llms-full.txt) in the Document Editor: design forms with validation in the browser.
- [PDF Forms](https://docs.textcontrol.com/tx-text-control-dotnet-server/pdf/forms/llms-full.txt): process forms in PDF documents.

---

## Nearby

- **Previous:** [Subtext Parts](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-processing/subtext-parts/llms-full.txt)
- **Next:** [Content Controls](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-processing/content-controls/llms-full.txt)
