{
  "category": "Text functions",
  "display_name": "TEXTJOIN",
  "entry_kind": "built_in_function",
  "eval_api": {
    "method": "POST",
    "url": "https://handbook.dnacalc.com/api/eval"
  },
  "function_id": "FUNC.TEXTJOIN",
  "implementation_state": {
    "answer_bank": null,
    "detail": "Recorded: 26 workbook cells.",
    "dnacalc_commit": "9e1884369a678158dd82d3d74188daf986995e87",
    "in_catalogue": true,
    "state": "matches",
    "state_label": "Matches every recorded Excel answer",
    "summary": "Matches all 26 recorded answers",
    "workbook_corpus": {
      "cells": 26,
      "matched": 26
    }
  },
  "implementations": [
    {
      "commit": "9e1884369a678158dd82d3d74188daf986995e87",
      "flavour": "excel-compatibility-candidate",
      "language": "Rust",
      "name": "CalcFunc",
      "own_code": [
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/text_functions.rs#L340-L342",
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/text_functions.rs#L181-L206",
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/text_functions.rs#L208-L240"
      ],
      "repository": "https://github.com/DnaCalc/DnaCalc",
      "shared_code": [
        "catalogue/text_functions::cells",
        "catalogue/text_functions::cell_text"
      ],
      "source": "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/text_functions.rs#L340-L342",
      "state": "matches",
      "suite": null,
      "summary": "Matches all 26 recorded answers"
    }
  ],
  "json_url": "https://handbook.dnacalc.com/api/functions/FUNC.TEXTJOIN.json",
  "name": "TEXTJOIN",
  "notes": [],
  "schema": "efh.function-reference/v1",
  "section_order": [
    "what-it-does",
    "try-it",
    "quirks",
    "how-to-implement",
    "version-differences",
    "alternatives"
  ],
  "sections": {
    "alternatives": "\n### Relationships\n\n\n- **`CONCAT`** is the same flattening concatenation without a delimiter and without\n  `ignore_empty`. **`CONCATENATE`** is the Compatibility-category ancestor of `CONCAT`:\n  Microsoft has replaced it with `CONCAT` and retains the old name so existing workbooks keep\n  working. `TEXTJOIN` is not part of that supersession chain — it is a distinct, later\n  function, not a renamed one, and nothing it does is deprecated.\n- **The `&` operator** is the two-item primitive. Everything above is sugar over it, and\n  `TEXTJOIN` is the sugar that also solves the trailing-separator and empty-item problems.\n- **`TEXTSPLIT`** is the inverse: delimiter-separated text back into an array. `TEXTJOIN` and\n  `TEXTSPLIT` round-trip only when no item contains the delimiter — the classic escaping\n  problem, which neither function addresses.\n- **[REPT](FUNC.REPT.md)** shares the result cap and its `#VALUE!`.\n- **[TEXT](FUNC.TEXT.md)** is the usual supplier of formatted items to a `TEXTJOIN` call.\n\n",
    "how-to-implement": "\n### Notes for implementers\n\n\nThe separator rule is \"between\", which in practice means the emit loop must track whether\nanything has been emitted yet rather than appending a delimiter after each item and trimming.\nThe trim approach breaks as soon as a legitimate item ends with the delimiter.\n\n`ignore_empty` interacts with that flag: a skipped item must not advance the \"something has\nbeen emitted\" state, or the result gains leading or doubled separators.\n\nThe 32,767-unit cap has to be checked as the result grows, not after it is built. `TEXTJOIN`\nover a large range can otherwise allocate far past the cap before discovering the documented\n`#VALUE!`.\n\nCounting for the cap is in UTF-16 code units, consistent with `LEN` and the value-universe\nchapter.\n\n\n",
    "quirks": "\n### Result and edge cases\n\n\nReturns `Text`.\n\nDocumented: the 32,767-character ceiling on the result, and `#VALUE!` when it is exceeded — the\nsame cap and the same enforcement side as [REPT](FUNC.REPT.md), and the reason those two are\nthe text functions most likely to hit it in practice. `TEXTJOIN` over a large range reaches the\ncap easily.\n\nOpen rather than settled:\n\n- **The Empty versus empty-text distinction.** `ignore_empty` is documented in terms of empty\n  *cells*. Whether an empty *string* argument, or an empty string inside an array literal, is\n  also skipped is a different question under the shared model, which keeps Empty and text\n  distinct ([The value universe](../model/01-value-universe.md)). Unverified.\n- **Non-text items.** Numbers, dates and logicals in the item list must be rendered to text,\n  and which rendering is used — general format, or something else — is a to-text question the\n  shared model states only in outline.\n- **Error items.** Whether an error in one of the joined cells propagates or is skipped.\n  Propagation is the default under the shared rules, but `TEXTJOIN` scans ranges, and range\n  scanning is where per-family policy lives.\n- **An array `delimiter`.** Whether a multi-item delimiter is cycled across the joins, or only\n  its first element is used, is a behaviour readers report and the Handbook has not checked.\n\n\n### Errors\n\n\n| Error | Condition | Source |\n|---|---|---|\n| `#VALUE!` | The result exceeds 32,767 characters. | Documented on Microsoft's `TEXTJOIN` page. |\n| — | Error values among the joined items. | Shared propagation rule; unverified for this function. |\n\n\n",
    "sources": "- Microsoft, \"TEXTJOIN function\" —\n  <https://support.microsoft.com/en-us/office/textjoin-function-357b449a-ec91-49d0-80c3-0e8fc845691c>\n  (signature, the delimiter and `ignore_empty` arguments, the number-treated-as-text rule, the\n  252-argument bound, the empty-delimiter concatenation use, and the 32,767-character\n  `#VALUE!`).\n- Handbook, [The value universe](../model/01-value-universe.md) — the text cap in UTF-16 code\n  units and the Empty versus text distinction.\n- Handbook, [Coercion and lifting](../model/02-coercion-and-lifting.md) — to-text conversion,\n  error propagation, and the direct-argument versus range-scan policy split.\n- Handbook projections `data/functions/FUNC.TEXTJOIN.json` (arity, no version marker) and\n  `data/presence/FUNC.TEXTJOIN.json` (sole-member implementing module, no open defect stream).\n\n",
    "version-differences": "No comparison between specific Excel builds is recorded here yet. This does not establish that all builds behave alike.",
    "what-it-does": "\n`TEXTJOIN(delimiter, ignore_empty, text1, [text2], …)` flattens its text arguments into one\nsequence of items and concatenates them with `delimiter` between consecutive items.\n\nTwo things distinguish it from `CONCAT` and from the `&` operator, and both are in the\nsignature:\n\n1. **The delimiter goes *between* items, not after them.** `n` items produce `n − 1`\n   separators. Getting this right by hand — trimming a trailing comma off a `&` chain — is the\n   chore the function exists to remove.\n2. **`ignore_empty` decides whether empty items count as items.** With `TRUE`, empty cells\n   contribute nothing and produce no separator; with `FALSE`, they contribute an empty item and\n   therefore still produce a separator, yielding runs of adjacent delimiters. This is the whole\n   reason the argument is mandatory rather than optional: there is no defensible default.\n\nRanges and arrays are flattened rather than treated as single values, so `TEXTJOIN(\", \", TRUE,\nA1:A10)` is a ten-item join, not a one-item one. That flattening is the function's real power\nand the reason it replaced the `&`-chain idiom.\n\n\n\n### Arguments\n\n\n| Argument | Meaning |\n|---|---|\n| `delimiter` | The separator placed between items. Required. Documented as text — empty, one or more characters in quotes, or a reference to text; a number supplied here is treated as text. |\n| `ignore_empty` | `TRUE` to skip empty items, `FALSE` to keep them. Required. |\n| `text1`, `text2`, … | The items to join: text values, ranges, or arrays. `text1` required; the rest optional and repeating. |\n\nAn empty `delimiter` reduces the function to plain concatenation, which Microsoft names as a\nsupported use.\n\n\n"
  },
  "signature": {
    "display": "TEXTJOIN(delimiter, ignore_empty, text1, [text2], ...)",
    "parameters": [
      {
        "description": null,
        "name": "delimiter",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "ignore_empty",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "text1",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "text2",
        "optional": true,
        "repeats": true
      }
    ],
    "trailing_repeats": true
  },
  "sources": {
    "metadata": {
      "admission": {
        "label": "implemented",
        "reason": null
      },
      "arity": {
        "max": 252,
        "min": 3
      },
      "category": "Text functions",
      "classification": {
        "arg_preparation_profile": "ValuesOnlyPreAdapter",
        "coercion_lift_profile": "Custom",
        "determinism_class": "Deterministic",
        "error_collapse_profile": "None",
        "fec_dependency_profile": "None",
        "host_interaction_class": "None",
        "kernel_signature_class": "TextToText",
        "rich_value_usage": "RichBlind",
        "surface_fec_dependency_profile": "RefOnly",
        "thread_safety_class": "SafePure",
        "volatility_class": "NonVolatile"
      },
      "descriptions": {
        "long": null,
        "short": "Texts joined with a delimiter, optionally skipping empty ones",
        "short_source": "dna-calc-own"
      },
      "docs": {
        "english_description": "Text: Combines the text from multiple ranges and/or strings",
        "microsoft_url": "https://support.microsoft.com/en-us/office/textjoin-function-357b449a-ec91-49d0-80c3-0e8fc845691c"
      },
      "entry_kind": "built_in_function",
      "localized_family_names": null,
      "localized_names": [
        {
          "locale": "ar-SA",
          "name": "TEXTJOIN"
        },
        {
          "locale": "bg-BG",
          "name": "TEXTJOIN"
        },
        {
          "locale": "cs-CZ",
          "name": "TEXTJOIN"
        },
        {
          "locale": "da-DK",
          "name": "TEKST.KOMBINER"
        },
        {
          "locale": "de-DE",
          "name": "TEXTJOIN"
        },
        {
          "locale": "el-GR",
          "name": "TEXTJOIN"
        },
        {
          "locale": "en-AU",
          "name": "TEXTJOIN"
        },
        {
          "locale": "en-GB",
          "name": "TEXTJOIN"
        },
        {
          "locale": "en-US",
          "name": "TEXTJOIN"
        },
        {
          "locale": "es-ES",
          "name": "UNIRCADENAS"
        },
        {
          "locale": "et-EE",
          "name": "TEXTJOIN"
        },
        {
          "locale": "fi-FI",
          "name": "TEKSTI.YHDISTÄ"
        },
        {
          "locale": "fr-FR",
          "name": "JOINDRE.TEXTE*"
        },
        {
          "locale": "he-IL",
          "name": "TEXTJOIN"
        },
        {
          "locale": "hr-HR",
          "name": "TEXTJOIN"
        },
        {
          "locale": "hu-HU",
          "name": "SZÖVEGÖSSZEFŰZÉS"
        },
        {
          "locale": "id-ID",
          "name": "TEXTJOIN"
        },
        {
          "locale": "it-IT",
          "name": "TEXTJOIN"
        },
        {
          "locale": "ja-JP",
          "name": "TEXTJOIN"
        },
        {
          "locale": "ko-KR",
          "name": "TEXTJOIN"
        },
        {
          "locale": "lt-LT",
          "name": "TEXTJOIN"
        },
        {
          "locale": "lv-LV",
          "name": "TEXTJOIN"
        },
        {
          "locale": "nb-NO",
          "name": "TEXTJOIN"
        },
        {
          "locale": "nl-NL",
          "name": "TEKST.COMBINEREN"
        },
        {
          "locale": "pl-PL",
          "name": "POŁĄCZ.TEKSTY"
        },
        {
          "locale": "pt-BR",
          "name": "TEXTJOIN"
        },
        {
          "locale": "pt-PT",
          "name": "UNIRTEXTO"
        },
        {
          "locale": "ro-RO",
          "name": "TEXTJOIN"
        },
        {
          "locale": "ru-RU",
          "name": "ОБЪЕДИНИТЬ"
        },
        {
          "locale": "sk-SK",
          "name": "TEXTJOIN"
        },
        {
          "locale": "sl-SI",
          "name": "TEXTJOIN"
        },
        {
          "locale": "sr-Latn-RS",
          "name": "TEXTJOIN"
        },
        {
          "locale": "sv-SE",
          "name": "TEXTJOIN"
        },
        {
          "locale": "th-TH",
          "name": "TEXTJOIN"
        },
        {
          "locale": "tr-TR",
          "name": "METİNBİRLEŞTİR"
        },
        {
          "locale": "uk-UA",
          "name": "TEXTJOIN"
        },
        {
          "locale": "vi-VN",
          "name": "TEXTJOIN"
        },
        {
          "locale": "zh-CN",
          "name": "TEXTJOIN"
        },
        {
          "locale": "zh-HK",
          "name": "TEXTJOIN"
        },
        {
          "locale": "zh-TW",
          "name": "TEXTJOIN"
        }
      ],
      "signature": {
        "display": "TEXTJOIN(delimiter, ignore_empty, text1, [text2], ...)",
        "parameters": [
          {
            "description": null,
            "name": "delimiter",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "ignore_empty",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "text1",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "text2",
            "optional": true,
            "repeats": true
          }
        ],
        "trailing_repeats": true
      },
      "surface_name": "TEXTJOIN",
      "version_marker": null,
      "xlcall": null
    },
    "microsoft": "https://support.microsoft.com/en-us/office/textjoin-function-357b449a-ec91-49d0-80c3-0e8fc845691c"
  },
  "try_it": {
    "formula": "=TEXTJOIN(\", \",TRUE,{\"a\";\"b\"})"
  },
  "url": "https://handbook.dnacalc.com/functions/TEXTJOIN.html",
  "variants": [],
  "versions": []
}