Nodes/comfyui-conditional-string-concat/Conditional String Concat
ComfyUI Node

Conditional String Concat

Toggling Prompt Fragments Without Retyping Them

By bravotan·Created 2 months ago·Updated 2 months ago· 0
Conditional String Concat
    • concatenated
    ◄separator, ►
    ◄text1►
    ◄enable1true►
    ◄text2►
    ◄enable2true►
    ◄text3►
    ◄enable3true►
    ◄text4►
    ◄enable4true►
    ◄text5►
    ◄enable5true►
    ◄text6►
    ◄enable6true►
    ◄text7►
    ◄enable7true►
    ◄text8►
    ◄enable8true►
    ◄text9►
    ◄enable9true►
    ◄text10►
    ◄enable10true►
    ◄text11►
    ◄enable11true►
    ◄text12►
    ◄enable12true►
    ◄text13►
    ◄enable13true►
    ◄text14►
    ◄enable14true►
    ◄text15►
    ◄enable15true►
    ◄text16►
    ◄enable16true►
    ◄text17►
    ◄enable17true►
    ◄text18►
    ◄enable18true►
    ◄text19►
    ◄enable19true►
    ◄text20►
    ◄enable20true►

    The problem this thing solves

    You have a prompt that works: a subject, a lighting phrase, a style tag, a couple of quality fragments. Some days you want the film-grain tag, some days you don't - and every time you flip you're back in the CLIP Text Encode box hand-deleting a phrase and hoping you retype it identically next week. Keeping three text encoders around and muting two gets ugly fast.

    Conditional String Concat is the boring fix: a bank of text boxes, each with its own checkbox, emitting one joined string containing only the parts you left ticked. No models, no dependencies, no cleverness - just a utils/string node in the plumbing layer that exists so you stop retyping prompt blocks.

    One thing up front: this pack has no community footprint - zero mentions across three years of the reddit corpus we index. Not alarming for a thirty-line string joiner, but there are no tutorials to fall back on either.

    How it actually joins

    The Python is tiny. It declares twenty slot pairs, text1/enable1 through text20/enable20, as optional inputs, plus one required separator. On run it walks slots 1–20, keeps a slot when enable is on and the text isn't just whitespace, and joins the survivors with your separator.

    The show/hide is frontend theatre on top: a small LiteGraph extension hides the widgets past however many slots you chose to display and stashes that count in the node's properties so it survives a save and reload. All twenty inputs exist on the backend regardless; the JS only hides boxes.

    Inputs and the one output

    Three fields matter:

    • separator (required, default ", ") - the join string for every gap. Leave it for tag prompts aimed at SDXL/Pony-lineage models. On a sentence-style prompt for an LLM-encoded model, commas between clauses read as noise, so set a single space instead. One separator covers the whole node, so "commas inside the tag block, blank line before the style block" isn't possible - block-structured prompting wants finer control.
    • text1…text20 (multiline, default empty) and enable1…enable20 (checkbox, default on). Ticking an empty slot does nothing, so the defaults are harmless.

    The two controls not in the schema are widgets the extension adds: + Add slot and - Remove slot. A fresh node shows two; grow it to twenty. The count saves per node, so a workflow you build with eight slots reopens with eight.

    One output: concatenated, a plain STRING. Wire it wherever a string goes - usually the text widget of a CLIP Text Encode (right-click → Convert widget to input if it isn't a socket yet), or a text-preview node when you want to eyeball the join first.

    Installing it

    No dependencies - empty dependency set in pyproject.toml, no requirements file - so installing is a folder copy and a restart.

    ComfyUI Manager: search "Conditional String Concat" and install, as the README says. If it comes up empty (one-person repo; Manager's index lags), do it by hand:

    cd ComfyUI/custom_nodes
    git clone https://github.com/bravotan/comfyui-conditional-string-concat.git
    

    It lands under utils/string - double-click the canvas search and type "concat". No model downloads, nothing to pip install. One metadata oddity: requires-python >= 3.12 in pyproject.toml. Nothing in the code needs it, and a plain clone never reads that line.

    The trap: a hidden slot is not a disabled slot

    Confirmed in both the README's own note and the code. - Remove slot hides the field; it doesn't clear it and it doesn't turn it off. Because the Python joins every enabled, non-empty slot whether or not it's visible, a slot you removed to tidy the node keeps contributing its text - invisibly. Re-adding it brings back whatever you typed. The checkbox is the on/off switch; remove is cosmetics. If the output contains a phrase you swear you deleted, count the slots before you blame the sampler.

    Smaller one: fragments are appended exactly as typed, with text.strip() used only to decide whether a slot counts. A stray trailing space survives into film grain , 85mm - double spacing that on some tag models is enough to matter.

    If the slots don't look right

    Hiding widgets from a LiteGraph extension is exactly the class of hack ComfyUI's Nodes 2.0 frontend rewrite breaks in third-party packs - the same breakage family that hit rgthree's rendering on the new canvas. If you opted in and the node seems stuck at two slots, or Add/Remove do nothing, switch back to the legacy canvas. Nothing is lost meanwhile: all twenty slots exist on the backend, so whatever boxes the UI shows you still join correctly.

    Last thing: for two whole prompt variants, two text encoders with one muted is fewer moving parts. This node earns its place at three or more fragments - when retyping them every run gets old.

    Categoryutils/string

    Inputs (41)

    NameTypeDefaultDescription
    separatorSTRING, —
    text1optSTRING—
    enable1optBOOLEANtrue—
    text2optSTRING—
    enable2optBOOLEANtrue—
    text3optSTRING—
    enable3optBOOLEANtrue—
    text4optSTRING—
    enable4optBOOLEANtrue—
    text5optSTRING—
    enable5optBOOLEANtrue—
    text6optSTRING—
    enable6optBOOLEANtrue—
    text7optSTRING—
    enable7optBOOLEANtrue—
    text8optSTRING—
    enable8optBOOLEANtrue—
    text9optSTRING—
    enable9optBOOLEANtrue—
    text10optSTRING—
    enable10optBOOLEANtrue—
    text11optSTRING—
    enable11optBOOLEANtrue—
    text12optSTRING—
    enable12optBOOLEANtrue—
    text13optSTRING—
    enable13optBOOLEANtrue—
    text14optSTRING—
    enable14optBOOLEANtrue—
    text15optSTRING—
    enable15optBOOLEANtrue—
    text16optSTRING—
    enable16optBOOLEANtrue—
    text17optSTRING—
    enable17optBOOLEANtrue—
    text18optSTRING—
    enable18optBOOLEANtrue—
    text19optSTRING—
    enable19optBOOLEANtrue—
    text20optSTRING—
    enable20optBOOLEANtrue—

    Outputs (1)

    NameTypeDescription
    concatenatedSTRING—