T2 Text Join
Build a prompt from named blocks, not one giant text box
- text
T2 Text Join (class TextJoin, from the conKORD/comfyui-text-tools pack, "T2 text tools") is a plain-string assembler. One separator, up to nine optional text slots, one joined string out. That's the whole node, and it looks trivial - which is exactly why it's useful.
Why you'd reach for it
Prompt modularization. The KB's "structure beats syntax" point is worth taking seriously: modern encoders read your prompt as a message, and keeping separate blocks clean keeps attributes from bleeding into each other. TextJoin gives you named slots to do that in the graph instead of inside a giant text box: quality, medium, background, actor, expression, dressing, action, tuning, and two catch-alls, whatever and more. Keep your quality tokens in one string, the character in another, the lighting in a third - then reuse each block across workflows, and swap one in without hunting through a wall of commas.
The neat part: empty or unconnected slots are skipped automatically. Build one workflow that serves several characters, and just wire in the blocks each run needs. No placeholder strings, no trailing ", , ,".
How it works
Pure join. It collects the connected slots, drops anything that's empty after stripping whitespace, and joins the rest in slot order with your separator. The one thing to know is the separator tooltip: "Use \n for new line." The two characters \n get converted into a real newline, which is how you build the block-structured prompts (tag block, blank line, natural-language description) that LLM-encoded models reward - and on SDXL-lineage models a clean block structure doesn't hurt either.
The inputs are forceInput sockets, which means they're built to accept wires rather than typed text. Connect a STRING source - another TextJoin, a LoRA trigger-word node, a text value node - or right-click a slot and convert the widget to input if you'd rather type.
The output
One text (STRING) socket, and it's the obvious consumer: a CLIP Text Encode, or any other node that wants a prompt string. Chain a couple of TextJoins if nine slots somehow aren't enough.
Installing it
Same pack as all the T2 nodes, and it's lightweight - pure Python, no models, no dependencies to download. Through ComfyUI Manager, search "comfyui-text-tools" (or "T2 text tools"). Manually:
cd ComfyUI/custom_nodes
git clone https://github.com/conKORD/comfyui-text-tools
Then restart ComfyUI. Keep the folder named comfyui-text-tools.
Troubleshooting
- A block isn't appearing? It's empty or not connected - the node skips those silently. That's a feature, not a bug. Don't wire in a placeholder like "none" expecting it to show up.
- Can't type in a slot?
forceInputsockets take wires by default. Convert the widget to input or drag a string from another node. - Prompt coming out as one run-on line? You're using a plain comma+space separator. Switch it to
\n(two characters, no quotes) for newline-separated blocks. - The pack README is the stock cookiecutter scaffold, so don't judge the node by it - the whole TextJoin implementation is about twenty lines in
nodes.pyat the repo root.
Inputs (11)
| Name | Type | Default | Description |
|---|---|---|---|
| separator | STRING | , | Use \n for new line |
| qualityopt | STRING | — | |
| mediumopt | STRING | — | |
| backgroundopt | STRING | — | |
| actoropt | STRING | — | |
| expressionopt | STRING | — | |
| dressingopt | STRING | — | |
| actionopt | STRING | — | |
| tuningopt | STRING | — | |
| whateveropt | STRING | — | |
| moreopt | STRING | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| text | STRING | — |