Nodes/ComfyUI-HTML-Note/HTML Note (saved with the json)
ComfyUI Node

HTML Note (saved with the json)

Put the manual inside the .json

By silno·Created a day ago·Updated a day ago· 1
HTML Note (saved with the json)
      ◄html►
      ◄height420►

      You know the feeling. Someone shares a workflow, you load it, and it's forty nodes of unlabelled spaghetti with one yellow note reading "steps 22". It runs, but the why didn't survive the trip. HTML Note fixes that: a note node that renders real HTML and stores it in the node, so it saves into the workflow .json and rides along with the file.

      What it actually is

      ComfyUI's built-in Note is fine for three words and a URL, and newer frontends register a MarkdownNote that renders markdown. Both are frontend virtual nodes: browser-only, yellow, filed under utilities. HTML Note is that idea one step further - the widget holds an HTML string and the node renders it in a small themed browser. Why not markdown? Because a useful note is rarely prose. It's a parameter table, a before/after box, a <details> with the whole prompt inside. Documents have tables. And it costs nothing: no models, no VRAM, no Python packages (the pack's dependencies list is empty and __init__.py imports os and nothing else), and no queue time.

      How the thing works

      The backend class is a stub on purpose: RETURN_TYPES = (), OUTPUT_NODE = False, and a noop whose body is return {}. ComfyUI needs a class to register a node, so there is one; it does nothing. All rendering is web/htmlnote.js, which hooks onNodeCreated and fills an <iframe> via srcdoc.

      Two details explain what you see. A string starting with <!doctype or <html passes through untouched, so your own <style> survives; anything else is a fragment wrapped in a skeleton that pulls ComfyUI's CSS variables, keeping tables readable in dark and light mode. And there is no sandbox: the iframe is same-origin, so canvas animations and small JS demos genuinely run.

      The inputs and outputs

      Two inputs, no outputs. html is a multiline STRING - the source box, which doubles as a socket: paste into it, or wire an upstream String (multiline) or note node into it. height is the INT for the widget area (120–8000, step 20, default 420).

      The upstream link is the clever part. With no outputs, this node gets pruned out of the execution graph - along with the note feeding it - so the value never reaches it at run time; the frontend reads the upstream's widgets_values straight off app.graph instead. So the preview updates live with no queueing, and when linked the node stores no copy: the upstream is the single source of truth and still travels inside the json. Pull the cable and it's editable again. The catch: the upstream must be a node whose value always exists on the graph, not something that only produces a string when it runs.

      Installing it

      Nothing to download, nothing to break. Manager → search HTML Note, or:

      cd ComfyUI/custom_nodes
      git clone https://github.com/silno/ComfyUI-HTML-Note
      # restart ComfyUI - custom nodes are imported once at startup
      

      The registry id is html-note, so comfy node install html-note works too. It asks for ComfyUI >=0.3.40 and is on 1.1.3. There's also a Node 18+ helper for docs that already exist as a file - node tools/inject_html.js workflow.json doc.html --height 420 - which injects the HTML into the last HTML Note in a workflow (or creates one) and backs the json up first.

      The failure everybody hits first

      You paste HTML and the preview stays empty. That isn't your markup. html is a multiline STRING, so ComfyUI generates its own native textarea on top of the one the plugin draws - two boxes, two unrelated strings. The plugin hides the native one and syncs them, so if you see two, your frontend JS is cached: hard refresh with Ctrl+Shift+R; one textarea should remain, under the toolbar; hit Reload, which re-reads the node's properties and widgets and logs len / propLen to the console; then Ctrl+S, because a refresh throws away unsaved content.

      Both fixed in 1.1.3: height used to do nothing because it hooked widget.onChange while the control actually fires on widget.callback, and on ComfyUI 1.53+ the top of the node could render black because the DOM-widget layer is position:fixed and hidden widgets still reported a height. Relative image paths also 404 - they resolve against the ComfyUI site root, so use absolute URLs or base64.

      Two things to decide before you commit

      Scripts run: no sandbox, so treat pasted HTML like code you're executing, and remember runtime state isn't saved - only the source travels in the json.

      Then there's sharing. HTMLNote is a custom node type, so anyone without the pack sees a red missing-node box where your documentation used to be. That's ordinary custom-node friction, and the one real argument for the built-in Markdown Note. Want tables, collapsible sections and a live demo inside the doc? This node. Just want pretty text everyone can read? Markdown is the lower-friction pick.

      CategoryNotes

      Inputs (2)

      NameTypeDefaultDescription
      htmlSTRING—
      heightINT420120–8000—

      Outputs (0)

      No outputs