{
  "id": "forms-ui",
  "title": "Accessible React forms",
  "summary": "GOV.UK-pattern form components for React (text, select, radios, checkboxes, dates, passwords, error summary) and the pure form state and checks behind them.",
  "synonyms": [
    "forms",
    "form ui",
    "react forms",
    "form components",
    "accessible forms",
    "gov.uk design system",
    "input fields",
    "validation messages",
    "form builder",
    "wizard"
  ],
  "apps": [
    "react form",
    "sign-up form",
    "checkout form",
    "multi-step form",
    "government service form",
    "admin data entry screens"
  ],
  "language": "python",
  "includes": [
    "validation-basics"
  ],
  "includedBy": [],
  "caveats": [
    "The components are React 19 and TypeScript only; the helpers (form.*) and the validation they pair with are in every language."
  ],
  "sections": [
    {
      "key": "state",
      "title": "Form state",
      "purpose": "Values, touched fields, errors and submit as a pure reducer, shared by browser and API.",
      "from": "forms-ui",
      "members": [
        {
          "id": "form.state",
          "tier": "core",
          "why": "initialFormState, formReducer and visibleErrors, for useReducer.",
          "section": "state",
          "from": "forms-ui",
          "version": "1.0.1",
          "summary": "A form's state as a pure reducer: values, touched fields, validator errors and the submit, for useReducer.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript"
          ],
          "available": false,
          "group": true,
          "functions": [
            "initialFormState",
            "formReducer",
            "visibleErrors"
          ],
          "signatures": [],
          "reference": null,
          "url": "http://www.functionalweave.com/functions/form.state"
        }
      ],
      "gaps": []
    },
    {
      "key": "fields",
      "title": "Fields",
      "purpose": "Labelled, hinted inputs with their errors wired up for screen readers (React, TypeScript only).",
      "from": "forms-ui",
      "members": [
        {
          "id": "react.form.form-field",
          "tier": "core",
          "why": "Wires a label, hint and error message to one control by id.",
          "section": "fields",
          "from": "forms-ui",
          "version": "1.0.1",
          "summary": "Wire a label, hint and error message to one form control by id, the accessible way (GOV.UK form group pattern).",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript"
          ],
          "available": false,
          "framework": {
            "name": "react",
            "range": "^19"
          },
          "group": true,
          "functions": [
            "fieldIds",
            "FormField"
          ],
          "signatures": [],
          "reference": null,
          "url": "http://www.functionalweave.com/functions/react.form.form-field"
        },
        {
          "id": "react.form.text-field",
          "tier": "core",
          "why": "Single-line text input with hint, error, autocomplete, prefix and suffix.",
          "section": "fields",
          "from": "forms-ui",
          "version": "1.0.1",
          "summary": "A labelled single-line text input with hint, error message, autocomplete, prefix and suffix (GOV.UK text input).",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript"
          ],
          "available": false,
          "framework": {
            "name": "react",
            "range": "^19"
          },
          "group": false,
          "functions": [
            "TextField"
          ],
          "signatures": [],
          "reference": null,
          "url": "http://www.functionalweave.com/functions/react.form.text-field"
        },
        {
          "id": "react.form.button",
          "tier": "core",
          "why": "Primary, secondary or warning button that stays focusable while loading.",
          "section": "fields",
          "from": "forms-ui",
          "version": "1.0.1",
          "summary": "A form button in primary, secondary or warning style that stays focusable while loading (GOV.UK button).",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript"
          ],
          "available": false,
          "framework": {
            "name": "react",
            "range": "^19"
          },
          "group": false,
          "functions": [
            "Button"
          ],
          "signatures": [],
          "reference": null,
          "url": "http://www.functionalweave.com/functions/react.form.button"
        },
        {
          "id": "react.form.textarea",
          "tier": "optional",
          "why": "Multi-line box with an optional live character or word count.",
          "section": "fields",
          "from": "forms-ui",
          "version": "1.0.1",
          "summary": "A labelled multi-line text box with hint, error and an optional live character or word count (GOV.UK).",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript"
          ],
          "available": false,
          "framework": {
            "name": "react",
            "range": "^19"
          },
          "group": false,
          "functions": [
            "Textarea"
          ],
          "signatures": [],
          "reference": null,
          "url": "http://www.functionalweave.com/functions/react.form.textarea"
        },
        {
          "id": "form.character-count",
          "tier": "optional",
          "why": "The \"You have 20 characters remaining\" message, in any language.",
          "section": "fields",
          "from": "forms-ui",
          "version": "1.0.1",
          "summary": "The GOV.UK character count message for a text box: characters or words left or over a limit, with a threshold.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "characterCount"
          ],
          "signatures": [
            "def character_count(text: str, limit: int, unit: CountUnit, threshold: Optional[int]) -> CharacterCount"
          ],
          "reference": "from fune.form.character_count import character_count  # form.character-count@^1",
          "url": "http://www.functionalweave.com/functions/form.character-count"
        },
        {
          "id": "react.form.select",
          "tier": "optional",
          "why": "Drop-down list with hint, error and an optional empty first option.",
          "section": "fields",
          "from": "forms-ui",
          "version": "1.0.1",
          "summary": "A labelled drop-down list with a hint, error message and an optional empty first option (GOV.UK select).",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript"
          ],
          "available": false,
          "framework": {
            "name": "react",
            "range": "^19"
          },
          "group": false,
          "functions": [
            "Select"
          ],
          "signatures": [],
          "reference": null,
          "url": "http://www.functionalweave.com/functions/react.form.select"
        },
        {
          "id": "react.form.password-field",
          "tier": "optional",
          "why": "Password input with Show/Hide and a live policy checklist.",
          "section": "fields",
          "from": "forms-ui",
          "version": "1.0.1",
          "summary": "A password input with a Show/Hide button and an optional live checklist of a password policy (GOV.UK password input).",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript"
          ],
          "available": false,
          "framework": {
            "name": "react",
            "range": "^19"
          },
          "group": true,
          "functions": [
            "passwordChecklist",
            "PasswordField"
          ],
          "signatures": [],
          "reference": null,
          "url": "http://www.functionalweave.com/functions/react.form.password-field"
        }
      ],
      "gaps": []
    },
    {
      "key": "choices",
      "title": "Choices",
      "purpose": "Questions answered by picking.",
      "from": "forms-ui",
      "members": [
        {
          "id": "react.form.radio-group",
          "tier": "optional",
          "why": "Choose one of several radios, with hints, an \"or\" divider and inline yes/no.",
          "section": "choices",
          "from": "forms-ui",
          "version": "1.0.1",
          "summary": "Choose exactly one of several radios, with item hints, an \"or\" divider and inline yes/no (GOV.UK radios).",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript"
          ],
          "available": false,
          "framework": {
            "name": "react",
            "range": "^19"
          },
          "group": false,
          "functions": [
            "RadioGroup"
          ],
          "signatures": [],
          "reference": null,
          "url": "http://www.functionalweave.com/functions/react.form.radio-group"
        },
        {
          "id": "react.form.checkbox-group",
          "tier": "optional",
          "why": "Tick any of several checkboxes, with an exclusive \"None\".",
          "section": "choices",
          "from": "forms-ui",
          "version": "1.0.1",
          "summary": "A question answered by ticking any of several checkboxes, with item hints and an exclusive \"None\" (GOV.UK checkboxes).",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript"
          ],
          "available": false,
          "framework": {
            "name": "react",
            "range": "^19"
          },
          "group": true,
          "functions": [
            "toggleValue",
            "CheckboxGroup"
          ],
          "signatures": [],
          "reference": null,
          "url": "http://www.functionalweave.com/functions/react.form.checkbox-group"
        },
        {
          "id": "react.form.checkbox",
          "tier": "optional",
          "why": "One checkbox such as \"I agree to the terms\".",
          "section": "choices",
          "from": "forms-ui",
          "version": "1.0.1",
          "summary": "One checkbox with its label beside it, such as \"I agree to the terms\" (GOV.UK single checkbox).",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript"
          ],
          "available": false,
          "framework": {
            "name": "react",
            "range": "^19"
          },
          "group": false,
          "functions": [
            "Checkbox"
          ],
          "signatures": [],
          "reference": null,
          "url": "http://www.functionalweave.com/functions/react.form.checkbox"
        },
        {
          "id": "react.form.fieldset",
          "tier": "optional",
          "why": "Groups related inputs under a legend with a shared hint and error.",
          "section": "choices",
          "from": "forms-ui",
          "version": "1.0.1",
          "summary": "Group related inputs under a legend, with a hint and error message described to the whole group (GOV.UK fieldset).",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript"
          ],
          "available": false,
          "framework": {
            "name": "react",
            "range": "^19"
          },
          "group": false,
          "functions": [
            "Fieldset"
          ],
          "signatures": [],
          "reference": null,
          "url": "http://www.functionalweave.com/functions/react.form.fieldset"
        }
      ],
      "gaps": []
    },
    {
      "key": "dates",
      "title": "Dates",
      "purpose": "Dates typed as day, month and year.",
      "from": "forms-ui",
      "members": [
        {
          "id": "react.form.date-input",
          "tier": "optional",
          "why": "Day, month and year boxes under one legend, marking the boxes in error.",
          "section": "dates",
          "from": "forms-ui",
          "version": "1.0.1",
          "summary": "Day, month and year boxes under one legend, with hint, error message and the boxes in error marked (GOV.UK date input).",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript"
          ],
          "available": false,
          "framework": {
            "name": "react",
            "range": "^19"
          },
          "group": false,
          "functions": [
            "DateInput"
          ],
          "signatures": [],
          "reference": null,
          "url": "http://www.functionalweave.com/functions/react.form.date-input"
        },
        {
          "id": "form.date-parts",
          "tier": "optional",
          "why": "Checks those three boxes with GOV.UK's error messages, in any language.",
          "section": "dates",
          "from": "forms-ui",
          "version": "1.0.1",
          "summary": "Check a date typed into day, month and year boxes, with GOV.UK's error messages and the boxes to mark in error.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "validateDateParts"
          ],
          "signatures": [
            "def validate_date_parts(parts: DateParts, label: str, rules: DateRules) -> DatePartsCheck"
          ],
          "reference": "from fune.form.date_parts import validate_date_parts  # form.date-parts@^1",
          "url": "http://www.functionalweave.com/functions/form.date-parts"
        }
      ],
      "gaps": []
    },
    {
      "key": "errors",
      "title": "Errors",
      "purpose": "Tell people what to fix.",
      "from": "forms-ui",
      "members": [
        {
          "id": "react.form.error-summary",
          "tier": "core",
          "why": "\"There is a problem\" box linking to each field in error, focused on arrival.",
          "section": "errors",
          "from": "forms-ui",
          "version": "1.0.1",
          "summary": "A \"There is a problem\" box linking to each field in error, focused on arrival, built from a validator's fields (GOV.UK).",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript"
          ],
          "available": false,
          "framework": {
            "name": "react",
            "range": "^19"
          },
          "group": true,
          "functions": [
            "errorSummaryItems",
            "ErrorSummary"
          ],
          "signatures": [],
          "reference": null,
          "url": "http://www.functionalweave.com/functions/react.form.error-summary"
        }
      ],
      "gaps": []
    },
    {
      "key": "styles",
      "title": "Styles",
      "purpose": "A default look you can theme.",
      "from": "forms-ui",
      "members": [
        {
          "id": "react.form.styles",
          "tier": "optional",
          "why": "Optional stylesheet for the caps-* classes, themed by --caps-form-* properties.",
          "section": "styles",
          "from": "forms-ui",
          "version": "1.0.1",
          "summary": "An optional stylesheet for the react.form elements' caps-* classes, themed by --caps-form-* custom properties.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript"
          ],
          "available": false,
          "framework": {
            "name": "react",
            "range": "^19"
          },
          "group": false,
          "functions": [
            "formStyles"
          ],
          "signatures": [],
          "reference": null,
          "url": "http://www.functionalweave.com/functions/react.form.styles"
        }
      ],
      "gaps": []
    },
    {
      "key": "contact",
      "title": "Contact details",
      "purpose": "Check and normalise a person's contact details before storing them.",
      "from": "validation-basics",
      "members": [
        {
          "id": "validation.email",
          "tier": "core",
          "why": "Is an email address plausible, by a documented subset of RFC 5322.",
          "section": "contact",
          "from": "validation-basics",
          "version": "1.0.0",
          "summary": "Is this a plausible email address? A documented, pragmatic subset of RFC 5322, not the full grammar.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "isEmail"
          ],
          "signatures": [
            "def is_email(value: str) -> bool"
          ],
          "reference": "from fune.validation.email import is_email  # validation.email@^1",
          "url": "http://www.functionalweave.com/functions/validation.email"
        },
        {
          "id": "validation.phone-e164",
          "tier": "core",
          "why": "Normalises a phone number to +44… E.164 for a default country.",
          "section": "contact",
          "from": "validation-basics",
          "version": "2.0.0",
          "summary": "Normalise a phone number to E.164 (+447700900123) using a default country's trunk and dialling prefixes.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "validatePhoneE164"
          ],
          "signatures": [
            "def validate_phone_e164(value: str, default_country: str) -> PhoneE164"
          ],
          "reference": "from fune.validation.phone_e164 import validate_phone_e164  # validation.phone-e164@^2",
          "url": "http://www.functionalweave.com/functions/validation.phone-e164"
        },
        {
          "id": "validation.uk-postcode",
          "tier": "core",
          "why": "Validates a UK postcode and puts it in canonical form.",
          "section": "contact",
          "from": "validation-basics",
          "version": "2.0.0",
          "summary": "Validate a UK postcode and normalise it to canonical upper case with one space before the inward code.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "validateUkPostcode"
          ],
          "signatures": [
            "def validate_uk_postcode(value: str) -> UkPostcode"
          ],
          "reference": "from fune.validation.uk_postcode import validate_uk_postcode  # validation.uk-postcode@^2",
          "url": "http://www.functionalweave.com/functions/validation.uk-postcode"
        },
        {
          "id": "text.normalise-name",
          "tier": "optional",
          "why": "Tidies a typed name: spacing and title case with Mc, O' and hyphen rules.",
          "section": "contact",
          "from": "validation-basics",
          "version": "1.0.0",
          "summary": "Tidy a personal name: trim, collapse whitespace and title-case, with Mc, Mac, O', hyphen and van/de rules.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "normaliseName"
          ],
          "signatures": [
            "def normalise_name(value: str) -> str"
          ],
          "reference": "from fune.text.normalise_name import normalise_name  # text.normalise-name@^1",
          "url": "http://www.functionalweave.com/functions/text.normalise-name"
        },
        {
          "id": "auth.normalise-email",
          "tier": "optional",
          "why": "Lower-cases an email's domain for storage and lookup.",
          "section": "contact",
          "from": "validation-basics",
          "version": "1.0.0",
          "summary": "Trim an email address and lower-case its domain for storage and lookup, or null if it is not a plausible address.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "normaliseEmail"
          ],
          "signatures": [
            "def normalise_email(value: str) -> Optional[str]"
          ],
          "reference": "from fune.auth.normalise_email import normalise_email  # auth.normalise-email@^1",
          "url": "http://www.functionalweave.com/functions/auth.normalise-email"
        }
      ],
      "gaps": []
    },
    {
      "key": "bank",
      "title": "Bank details",
      "purpose": "Check payee and customer bank details before money moves.",
      "from": "validation-basics",
      "members": [
        {
          "id": "validation.iban",
          "tier": "core",
          "why": "Checks an IBAN's mod-97 checksum and its country's length.",
          "section": "bank",
          "from": "validation-basics",
          "version": "1.0.0",
          "summary": "Check an IBAN against the ISO 13616 mod-97-10 checksum and the registered length for its country.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "isIban"
          ],
          "signatures": [
            "def is_iban(value: str) -> bool"
          ],
          "reference": "from fune.validation.iban import is_iban  # validation.iban@^1",
          "url": "http://www.functionalweave.com/functions/validation.iban"
        },
        {
          "id": "validation.bic",
          "tier": "optional",
          "why": "Checks a SWIFT/BIC code's format and splits it.",
          "section": "bank",
          "from": "validation-basics",
          "version": "1.0.0",
          "summary": "Check the format of a SWIFT/BIC code (8 or 11 characters) and split it into its parts.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "validateBic"
          ],
          "signatures": [
            "def validate_bic(value: str) -> BicCheck"
          ],
          "reference": "from fune.validation.bic import validate_bic  # validation.bic@^1",
          "url": "http://www.functionalweave.com/functions/validation.bic"
        },
        {
          "id": "validation.uk-sort-code-account",
          "tier": "optional",
          "why": "Checks a UK sort code and account number by the Vocalink modulus rules, against a table you supply.",
          "section": "bank",
          "from": "validation-basics",
          "version": "3.0.0",
          "summary": "Check a UK sort code and account number with the Vocalink/Pay.UK modulus rules, against a table you supply.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "validateUkSortCodeAccount"
          ],
          "signatures": [
            "def validate_uk_sort_code_account(sort_code: str, account_number: str, table: UkModulusTable) -> UkSortCodeAccount"
          ],
          "reference": "from fune.validation.uk_sort_code_account import validate_uk_sort_code_account  # validation.uk-sort-code-account@^3",
          "url": "http://www.functionalweave.com/functions/validation.uk-sort-code-account"
        },
        {
          "id": "validation.uk-modulus-table",
          "tier": "optional",
          "why": "Parses Vocalink's VALACDOS and SCSUBTAB files into that table.",
          "section": "bank",
          "from": "validation-basics",
          "version": "1.0.0",
          "summary": "Parse Vocalink's VALACDOS.txt and SCSUBTAB.txt into the table UK sort code modulus checking needs.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "parseUkModulusTable"
          ],
          "signatures": [
            "def parse_uk_modulus_table(valacdos: str, scsubtab: str) -> UkModulusTable"
          ],
          "reference": "from fune.validation.uk_modulus_table import parse_uk_modulus_table  # validation.uk-modulus-table@^1",
          "url": "http://www.functionalweave.com/functions/validation.uk-modulus-table"
        }
      ],
      "gaps": []
    },
    {
      "key": "check-digits",
      "title": "Identifiers and check digits",
      "purpose": "Catch mistyped reference numbers by their check digits.",
      "from": "validation-basics",
      "members": [
        {
          "id": "validation.luhn",
          "tier": "optional",
          "why": "Luhn mod-10 check, for card numbers and many reference numbers.",
          "section": "check-digits",
          "from": "validation-basics",
          "version": "1.0.0",
          "summary": "Check a digit string against the Luhn mod-10 checksum used by payment cards and many identifiers.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "isLuhn"
          ],
          "signatures": [
            "def is_luhn(value: str) -> bool"
          ],
          "reference": "from fune.validation.luhn import is_luhn  # validation.luhn@^1",
          "url": "http://www.functionalweave.com/functions/validation.luhn"
        },
        {
          "id": "validation.uk-company-number",
          "tier": "optional",
          "why": "Checks a Companies House number's format and prefix.",
          "section": "check-digits",
          "from": "validation-basics",
          "version": "2.0.1",
          "summary": "Check a Companies House company number's format and prefix (SC, NI, OC, LP...) and zero-pad it to eight characters.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "validateUkCompanyNumber"
          ],
          "signatures": [
            "def validate_uk_company_number(value: str) -> UkCompanyNumber"
          ],
          "reference": "from fune.validation.uk_company_number import validate_uk_company_number  # validation.uk-company-number@^2",
          "url": "http://www.functionalweave.com/functions/validation.uk-company-number"
        },
        {
          "id": "validation.lei",
          "tier": "optional",
          "why": "Checks a Legal Entity Identifier's check digits.",
          "section": "check-digits",
          "from": "validation-basics",
          "version": "1.0.0",
          "summary": "Check a 20-character Legal Entity Identifier against its ISO 17442 / ISO 7064 MOD 97-10 check digits.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "validateLei"
          ],
          "signatures": [
            "def validate_lei(value: str) -> LeiCheck"
          ],
          "reference": "from fune.validation.lei import validate_lei  # validation.lei@^1",
          "url": "http://www.functionalweave.com/functions/validation.lei"
        },
        {
          "id": "validation.gtin",
          "tier": "optional",
          "why": "Checks an EAN/UPC/GTIN barcode number.",
          "section": "check-digits",
          "from": "validation-basics",
          "version": "1.1.0",
          "summary": "Check an EAN-8, UPC-A, EAN-13 or GTIN-14 barcode number against the GS1 mod-10 check digit.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "validateGtin"
          ],
          "signatures": [
            "def validate_gtin(value: str) -> GtinCheck"
          ],
          "reference": "from fune.validation.gtin import validate_gtin  # validation.gtin@^1",
          "url": "http://www.functionalweave.com/functions/validation.gtin"
        }
      ],
      "gaps": []
    },
    {
      "key": "masking",
      "title": "Displaying sensitive values",
      "purpose": "Show stored identifiers without exposing them.",
      "from": "validation-basics",
      "members": [
        {
          "id": "text.mask",
          "tier": "optional",
          "why": "Masks all but the last digits of a card, account or phone number.",
          "section": "masking",
          "from": "validation-basics",
          "version": "1.0.0",
          "summary": "Mask all but the last n characters of a card, account or phone number, optionally keeping separators.",
          "status": "stable",
          "license": "NOASSERTION",
          "languages": [
            "typescript",
            "python",
            "rust"
          ],
          "available": true,
          "group": false,
          "functions": [
            "mask"
          ],
          "signatures": [
            "def mask(value: str, visible: int, mask_char: str, keep_separators: bool) -> str"
          ],
          "reference": "from fune.text.mask import mask  # text.mask@^1",
          "url": "http://www.functionalweave.com/functions/text.mask"
        }
      ],
      "gaps": []
    }
  ],
  "gaps": [
    {
      "key": "other-frameworks",
      "text": "Vue, Svelte, Angular or React Native components: only React is covered.",
      "section": null,
      "from": "forms-ui"
    },
    {
      "key": "multi-step-flows",
      "text": "Multi-page journeys: routing between steps, check-your-answers pages and saving progress.",
      "section": null,
      "from": "forms-ui"
    },
    {
      "key": "file-upload",
      "text": "File upload fields with progress, type and size checks.",
      "section": null,
      "from": "forms-ui"
    },
    {
      "key": "autocomplete",
      "text": "Autocomplete or combobox inputs (address finder, country picker).",
      "section": null,
      "from": "forms-ui"
    },
    {
      "key": "submission",
      "text": "Posting the form, CSRF protection and showing server errors back in the fields.",
      "section": null,
      "from": "forms-ui"
    },
    {
      "key": "address-lookup",
      "text": "Turning a postcode into a list of addresses (Royal Mail PAF or a lookup API) is network work and not in caps.",
      "section": null,
      "from": "validation-basics"
    },
    {
      "key": "email-deliverability",
      "text": "Whether a mailbox exists (MX lookups, a confirmation email): validation.email checks the syntax only.",
      "section": null,
      "from": "validation-basics"
    },
    {
      "key": "vocalink-data",
      "text": "The Vocalink modulus tables themselves: download them from Pay.UK under its terms; caps parses them but does not ship them.",
      "section": null,
      "from": "validation-basics"
    }
  ],
  "counts": {
    "members": 30,
    "core": 9,
    "optional": 21,
    "unreviewed": 0,
    "deprecated": [],
    "unavailable": [
      "form.state",
      "react.form.form-field",
      "react.form.text-field",
      "react.form.button",
      "react.form.textarea",
      "react.form.select",
      "react.form.password-field",
      "react.form.radio-group",
      "react.form.checkbox-group",
      "react.form.checkbox",
      "react.form.fieldset",
      "react.form.date-input",
      "react.form.error-summary",
      "react.form.styles"
    ],
    "missing": [],
    "gaps": 8
  },
  "warnings": [
    "not written in python: form.state, react.form.form-field, react.form.text-field, react.form.button, react.form.textarea, react.form.select, react.form.password-field, react.form.radio-group, react.form.checkbox-group, react.form.checkbox, react.form.fieldset, react.form.date-input, react.form.error-summary, react.form.styles",
    "The components are React 19 and TypeScript only; the helpers (form.*) and the validation they pair with are in every language."
  ],
  "url": "http://www.functionalweave.com/suites/forms-ui",
  "owner": null
}
