Text functions
TEXTJOIN
Matches all 26 recorded answers
Recorded: 26 workbook cells. How we measure this · See the Rust code
Local names in 40 languages
| Language | Name in Excel |
|---|---|
| Arabic | TEXTJOIN |
| Bulgarian | TEXTJOIN |
| Czech | TEXTJOIN |
| Danish | TEKST.KOMBINER |
| German | TEXTJOIN |
| Greek | TEXTJOIN |
| English (Australia) | TEXTJOIN |
| English (United Kingdom) | TEXTJOIN |
| English (United States) | TEXTJOIN |
| Spanish | UNIRCADENAS |
| Estonian | TEXTJOIN |
| Finnish | TEKSTI.YHDISTÄ |
| French | JOINDRE.TEXTE |
| Hebrew | TEXTJOIN |
| Croatian | TEXTJOIN |
| Hungarian | SZÖVEGÖSSZEFŰZÉS |
| Indonesian | TEXTJOIN |
| Italian | TEXTJOIN |
| Japanese | TEXTJOIN |
| Korean | TEXTJOIN |
| Lithuanian | TEXTJOIN |
| Latvian | TEXTJOIN |
| Norwegian | TEXTJOIN |
| Dutch | TEKST.COMBINEREN |
| Polish | POŁĄCZ.TEKSTY |
| Portuguese (Brazil) | TEXTJOIN |
| Portuguese (Portugal) | UNIRTEXTO |
| Romanian | TEXTJOIN |
| Russian | ОБЪЕДИНИТЬ |
| Slovak | TEXTJOIN |
| Slovenian | TEXTJOIN |
| Serbian (Latin) | TEXTJOIN |
| Swedish | TEXTJOIN |
| Thai | TEXTJOIN |
| Turkish | METİNBİRLEŞTİR |
| Ukrainian | TEXTJOIN |
| Vietnamese | TEXTJOIN |
| Chinese (Simplified) | TEXTJOIN |
| Chinese (Hong Kong) | TEXTJOIN |
| Chinese (Traditional) | TEXTJOIN |
Names from Microsoft's support site.
What it does
TEXTJOIN(delimiter, ignore_empty, text1, [text2], ...)
TEXTJOIN(delimiter, ignore_empty, text1, [text2], …) flattens its text arguments into one
sequence of items and concatenates them with delimiter between consecutive items.
Two things distinguish it from CONCAT and from the & operator, and both are in the
signature:
- The delimiter goes between items, not after them.
nitems producen − 1separators. Getting this right by hand — trimming a trailing comma off a&chain — is the chore the function exists to remove. ignore_emptydecides whether empty items count as items. WithTRUE, empty cells contribute nothing and produce no separator; withFALSE, they contribute an empty item and therefore still produce a separator, yielding runs of adjacent delimiters. This is the whole reason the argument is mandatory rather than optional: there is no defensible default.
Ranges and arrays are flattened rather than treated as single values, so TEXTJOIN(", ", TRUE, A1:A10) is a ten-item join, not a one-item one. That flattening is the function's real power
and the reason it replaced the &-chain idiom.
Arguments
| Argument | Meaning |
|---|---|
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. |
ignore_empty | TRUE to skip empty items, FALSE to keep them. Required. |
text1, text2, … | The items to join: text values, ranges, or arrays. text1 required; the rest optional and repeating. |
An empty delimiter reduces the function to plain concatenation, which Microsoft names as a
supported use.
Try it
Quirks
Result and edge cases
Returns Text.
Documented: the 32,767-character ceiling on the result, and #VALUE! when it is exceeded — the
same cap and the same enforcement side as REPT, and the reason those two are
the text functions most likely to hit it in practice. TEXTJOIN over a large range reaches the
cap easily.
Open rather than settled:
- The Empty versus empty-text distinction.
ignore_emptyis documented in terms of empty cells. Whether an empty string argument, or an empty string inside an array literal, is also skipped is a different question under the shared model, which keeps Empty and text distinct (The value universe). Unverified. - Non-text items. Numbers, dates and logicals in the item list must be rendered to text, and which rendering is used — general format, or something else — is a to-text question the shared model states only in outline.
- Error items. Whether an error in one of the joined cells propagates or is skipped.
Propagation is the default under the shared rules, but
TEXTJOINscans ranges, and range scanning is where per-family policy lives. - An array
delimiter. Whether a multi-item delimiter is cycled across the joins, or only its first element is used, is a behaviour readers report and the Handbook has not checked.
Errors
| Error | Condition | Source |
|---|---|---|
#VALUE! | The result exceeds 32,767 characters. | Documented on Microsoft's TEXTJOIN page. |
| — | Error values among the joined items. | Shared propagation rule; unverified for this function. |
How to implement
Notes for implementers
The separator rule is "between", which in practice means the emit loop must track whether anything has been emitted yet rather than appending a delimiter after each item and trimming. The trim approach breaks as soon as a legitimate item ends with the delimiter.
ignore_empty interacts with that flag: a skipped item must not advance the "something has
been emitted" state, or the result gains leading or doubled separators.
The 32,767-unit cap has to be checked as the result grows, not after it is built. TEXTJOIN
over a large range can otherwise allocate far past the cap before discovering the documented
#VALUE!.
Counting for the cap is in UTF-16 code units, consistent with LEN and the value-universe
chapter.
Rust code
Show the CalcFunc source of this function
Quoted from the public repository DnaCalc/DnaCalc, crates calc-func and calc-fml, at commit 9e1884369a67. Comments are the source's own. A kernel shared with other functions appears once, on its module page.
TEXTJOIN · 3 lines · calc-func/src/catalogue/text_functions.rs on GitHub30 textjoin_fn "TEXTJOIN" (3, 252) [R "delimiter", V "ignore_empty", R "text1", R "text2"] |s, a, sv| {
textjoin(s, a, sv)
}
delimiters · 26 lines · calc-func/src/catalogue/text_functions.rs on GitHub/// TEXTJOIN's delimiters: one text, or each cell of a reference or an array in turn, used in
/// order and again from the first (Microsoft's TEXTJOIN page: a range of delimiters). A reference
/// of several areas (a 3-D reference) gives the cells of each area in its order (Excel 16.0.20430,
/// 2026-10-25, dc-6au, sheets Ja, Fe and Ma holding 1, 2, 3 in A1 and 100, 200, 300 in A2:
/// `=TEXTJOIN(Ja:Ma!A1,1,"a","b")` "a1b", `=TEXTJOIN(Ja:Ma!A1:A2,1,"a","b","c")` "a1b100c",
/// `=TEXTJOIN(Fe:Ma!A1,1,"a","b","c")` "a2b3c").
fn delimiters(site: &Site<'_>, a: &[CalcValue], sv: &mut crate::call::EvalServices<'_>) -> Step<Vec<Vec<u16>>> {
let mut found = Vec::new();
match a[0].core_ref() {
CoreRef::Reference(reference) => {
for &area in reference.areas() {
let one = [CalcValue::reference(crate::value::ReferenceLike::area(area))];
for value in &grid(site, &one, 0, sv)?.cells {
found.push(cell_text(site, 0, value)?);
}
}
}
CoreRef::Array(_) => {
for value in &cells(site, a, 0, sv)?.cells {
found.push(cell_text(site, 0, value)?);
}
}
_ => found.push(text_arg(site, a, 0)?.utf16_code_units().to_vec()),
}
Ok(found)
}
textjoin · 33 lines · calc-func/src/catalogue/text_functions.rs on GitHubfn textjoin(site: &Site<'_>, a: &[CalcValue], sv: &mut crate::call::EvalServices<'_>) -> Step<CalcValue> {
let delimiters = delimiters(site, a, sv)?;
let ignore_empty = num(site, a, 1)? != 0.0;
let mut joined: Vec<u16> = Vec::new();
let mut parts = 0usize;
for index in 2..a.len() {
let g = cells(site, a, index, sv)?;
for value in &g.cells {
if ignore_empty && matches!(value.core_ref(), CoreRef::Empty | CoreRef::Missing) {
continue;
}
let units = cell_text(site, index, value)?;
if ignore_empty && units.is_empty() {
continue;
}
let delimiter: &[u16] = if delimiters.is_empty() {
&[]
} else {
&delimiters[parts.saturating_sub(1) % delimiters.len()]
};
let extra = units.len() + if parts == 0 { 0 } else { delimiter.len() };
if joined.len() + extra > EXCEL_TEXT_MAX_UTF16_CODE_UNITS {
return fail(WorksheetErrorCode::Calc);
}
if parts > 0 {
joined.extend_from_slice(delimiter);
}
joined.extend_from_slice(&units);
parts += 1;
}
}
Ok(CalcValue::text(ExcelText::from_utf16_code_units(joined)))
}
Kernels shared with other functions
Argument and result plumbing
No implementation has been published with a Handbook test suite for this function.
Version differences
No comparison between specific Excel builds is recorded here yet. This does not establish that all builds behave alike.
Alternatives
Relationships
CONCATis the same flattening concatenation without a delimiter and withoutignore_empty.CONCATENATEis the Compatibility-category ancestor ofCONCAT: Microsoft has replaced it withCONCATand retains the old name so existing workbooks keep working.TEXTJOINis not part of that supersession chain — it is a distinct, later function, not a renamed one, and nothing it does is deprecated.- The
&operator is the two-item primitive. Everything above is sugar over it, andTEXTJOINis the sugar that also solves the trailing-separator and empty-item problems. TEXTSPLITis the inverse: delimiter-separated text back into an array.TEXTJOINandTEXTSPLITround-trip only when no item contains the delimiter — the classic escaping problem, which neither function addresses.- REPT shares the result cap and its
#VALUE!. - TEXT is the usual supplier of formatted items to a
TEXTJOINcall.
Named variants
No named variants are recorded yet.
Suggest a correction or contribute an implementation · For agents