@form2js/dom

March 21, 2026 ยท View on GitHub

@form2js/dom solves the browser side of the problem: walk a form or DOM subtree, extract the submitted values, and return the parsed object. Use it when you want native form semantics without writing the extraction logic yourself.

Installation

npm install @form2js/dom

Standalone via unpkg:

<script src="https://unpkg.com/@form2js/dom/dist/standalone.global.js"></script>
<script>
  const data = formToObject(formElement);
  // or form2js(formElement)
</script>

General Example

import { formToObject } from "@form2js/dom";

const result = formToObject(document.getElementById("profileForm"), {
  useIdIfEmptyName: true,
  getDisabled: false,
});

Types and Properties

Exported Surface

ExportKindWhat it does
NodeCallbackResultinterfaceCustom extraction payload (name or key plus value).
FormToObjectNodeCallbacktypeCallback type used during node walk.
ExtractOptionsinterfaceOptions for pair extraction only.
FormToObjectOptionsinterfaceExtraction options plus parser options.
RootNodeInputtypeSupported root inputs such as id, Node, NodeList, arrays, and collections.
extractPairsfunctionTraverses DOM and returns path/value entries.
formToObjectfunctionHigh-level parser from DOM to object tree.
form2jsfunctionCompatibility wrapper around formToObject.
export interface NodeCallbackResult {
  name?: string;
  key?: string;
  value: unknown;
}

export const SKIP_NODE: unique symbol;

export type FormToObjectNodeCallback = (
  node: Node
) => NodeCallbackResult | typeof SKIP_NODE | false | null | undefined;

export interface ExtractOptions {
  nodeCallback?: FormToObjectNodeCallback;
  useIdIfEmptyName?: boolean;
  getDisabled?: boolean;
  document?: Document;
}

export interface FormToObjectOptions extends ExtractOptions, ParseOptions {}

export function extractPairs(rootNode: RootNodeInput, options?: ExtractOptions): Entry[];
export function formToObject(rootNode: RootNodeInput, options?: FormToObjectOptions): ObjectTree;

Options And Defaults

OptionDefaultWhereWhy this matters
delimiter"."formToObject, form2jsMatches parser path semantics.
skipEmptytrueformToObject, form2jsSkips "" and null values by default.
allowUnsafePathSegmentsfalseformToObject, form2jsRejects unsafe path segments before object merging.
useIdIfEmptyNamefalseextraction and wrappersLets id act as field key when name is empty.
getDisabledfalseextraction and wrappersDisabled controls, including disabled fieldset descendants, are ignored unless enabled explicitly.
nodeCallbackunsetextraction and wrappersUse it for custom field extraction from specific nodes.
documentambient/global documentextraction and wrappersRequired outside browser globals.

useIdIfEmptyName

Enable this when a form control is keyed by id rather than name, which is common in older markup or UI builders.

import { formToObject } from "@form2js/dom";

const result = formToObject(document.getElementById("profileForm"), {
  useIdIfEmptyName: true
});

nodeCallback

Use nodeCallback to rewrite or skip specific nodes before the default extraction logic runs.

import { formToObject, SKIP_NODE } from "@form2js/dom";

const result = formToObject(document.getElementById("profileForm"), {
  nodeCallback(node) {
    if (!(node instanceof HTMLInputElement)) {
      return;
    }

    if (node.type === "hidden" && node.name === "csrfToken") {
      return SKIP_NODE;
    }

    if (node.name === "person.age") {
      return { key: node.name, value: Number(node.value) };
    }
  }
});

Behavior Notes

  • select name="colors[]" is emitted as key colors; the trailing [] is removed for selects.
  • Checkbox and radio values follow native browser submission semantics:
    • checked controls emit their string value
    • unchecked controls are omitted
    • omitted indexed controls do not reserve compacted array slots, so preserve row identity with another submitted field when it matters
  • Button-like inputs (button, reset, submit, image) are excluded from extraction.
  • You can merge multiple roots (NodeList, arrays, HTMLCollection) into one object.
  • If the callback returns SKIP_NODE, that node is excluded from extraction entirely.
  • If the callback returns { key | name, value }, that value is used directly for that node.