#3479·shepherd

Docs: rendering framework components as step content, and why DOM injection belongs in when.show

Author: chuckcarpenterCreated Aug 13, 2026Updated Aug 13, 2026
Labelsdocumentation

Split out of #2533 and #3216. Both reporters hit the same documentation gap from different directions, and both waited a long time for an answer that should have been a docs link.

What's missing

1. Rendering a framework component as step content.

StepText accepts an HTMLElement, and shepherd-text.ts appends it directly rather than serialising it — so you can mount a live Vue/React/Svelte component to a detached node and hand that node to text, keeping reactivity and event handlers intact. Nothing in the docs says this. #2533 asked for it in Dec 2023, was told "pass HTML", asked for a demo, and never got one.

Worth documenting alongside it: the dialog chrome is Shepherd's own DOM, but everything inside is opt-out — no title/cancelIcon means no header, an empty buttons array means no footer, and arrow: false drops the arrow. With those off a component owns the entire body, which is what people asking this question actually want.

2. Why custom footer/DOM injection has to happen in when.show.

The step element is torn down and rebuilt on every show (_teardownElements() / _setupElements()), and createShepherdFooter builds a fresh <footer> each time. So a one-time DOM injection cannot survive a step change. #3216 spent a retry loop and a setTimeout ladder working around this without ever being told the element is simply recreated.

Two sharp edges belong in the same section:

  • Inside when.show, this is the Step — an arrow function silently breaks this.getElement().
  • A per-step when replaces defaultStepOptions.when wholesale (shallow Object.assign in _setOptions).
  • Scope queries with this.getElement() rather than document.querySelector, which returns the first match in document order and will find a previous step's node, since hidden steps stay attached.

Suggested home

docs-src/src/content/docs/recipes/cookbook.md already demonstrates the when.show pattern for progress indicators without explaining why it must be that hook — extending that recipe and adding a "custom content / framework components" entry would cover both.