Repository: wagtail/wagtail
File: client/src/controllers/TeleportController.ts (TypeScript)

Code before:
      // (including text nodes).
      switch (this.modeValue) {
        case TeleportMode.outerHTML:
          target.replaceWith(this.templateFragment);
          break;
        case TeleportMode.innerHTML:
          target.innerHTML = '';
          target.append(this.templateFragment);
          break;
        case TeleportMode.textContent:
          target.textContent = this.templateFragment.textContent;
          break;
        case TeleportMode.beforebegin:
          target.parentElement?.insertBefore(this.templateFragment, target);
          break;
        case TeleportMode.afterbegin:
          target.prepend(this.templateFragment);
          break;
        case TeleportMode.beforeend:
          target.append(this.templateFragment);
          break;
        case TeleportMode.afterend:
          target.parentElement?.insertBefore(
            this.templateFragment,
            target.nextSibling,
          );
          break;
        default:
          target.append(this.templateFragment);
          break;
      }

      this.dispatch('appended', { cancelable: false, detail: { target } });
      completed = true;
      if (this.keepValue) return;
      this.element.remove();
    };

    const event = this.dispatch('append', {
      cancelable: true,
      detail: { complete, target },
    });

    if (!event.defaultPrevented) complete();
  }

  /**
   * Resolve a valid target element, defaulting to the document.body
   * or the shadow root's first DOM node if no target selector provided.
   */
  get target() {

Review comment (suggestion):
From MDN:

> [`referenceNode`](https://developer.mozilla.org/en-US/docs/Web/API/Node/insertBefore#referencenode)
> The node before which `newNode` is inserted. If this is `null`, then `newNode` is inserted at the end of node's child nodes.

where

- (current) node = `target`
- `newNode` = `this.templateFragment`
- `referenceNode` = `target.nextSibling`

So if the target doesn't have a next sibling, `afterend` will still work correctly.

Code after:
      // the template, and allows the template to contain any type of content
      // (including text nodes).
      switch (this.modeValue) {
        case TeleportMode.outerHTML:
          target.replaceWith(this.templateFragment);
          break;
        case TeleportMode.innerHTML:
          target.innerHTML = '';
          target.append(this.templateFragment);
          break;
        case TeleportMode.textContent:
          target.textContent = this.templateFragment.textContent;
          break;
        case TeleportMode.beforebegin:
          target.parentElement?.insertBefore(this.templateFragment, target);
          break;
        case TeleportMode.afterbegin:
          target.prepend(this.templateFragment);
          break;
        case TeleportMode.beforeend:
          target.append(this.templateFragment);
          break;
        case TeleportMode.afterend:
          target.parentElement?.insertBefore(
            this.templateFragment,
            target.nextSibling,
          );
          break;
        default:
          target.append(this.templateFragment);
          break;
      }

      this.dispatch('appended', { cancelable: false, detail: { target } });
      completed = true;
      if (this.keepValue) return;
      this.element.remove();
    };

    const event = this.dispatch('append', {
      cancelable: true,
      detail: { complete, target },
    });

    if (!event.defaultPrevented) complete();
  }

  /**
   * Resolve a valid target element, defaulting to the document.body
   * or the shadow root's first DOM node if no target selector provided.
   */