[whatwg/dom] Improve API of `insertAdjacent*()` methods (Issue #1251)

### What problem are you trying to solve?

`insertAdjacentHTML()` is fantastic for templating. It bridged an old usability cliff where authors had to either give up working with HTML strings, or do a lot of painful wrangling with `innerHTML` if they only wanted to insert an HTML fragment inside or relative to another element, rather than replace the entire contents of an element.

However, due to its origins, the API is …let’s say suboptimal and clumsy.
The position arguments are excessively long and inconsistent with related DOM methods (e.g. `child.before()` but `"beforebegin"`), and there’s not even a default for the first argument, so authors are forced to specify them on every call.

Furthermore, we also have `insertAdjacentElement()` and `insertAdjacentText()` methods, which are simply worse APIs for `before()` / `after()` / `append()` / `prepend()`, presumably included for compat.

### What solutions exist today?

_No response_

### How would you solve it?

### Option 1: Overloading `insertAdjacent*()` methods

1. Deprecate existing position strings, and instead move to:
 - `"before"` instead of `"beforebegin"`
 - `"after"` instead of `"afterend"`
 - `"start"` (or `"prepend"`?) instead of `"afterbegin"`
 - `"end"` (or `"append"`?) instead of `"beforeend"`
2. Default `position` to `"end"` 

Option 1b: Instead of overloading the signature with a one argument signature to default `position`, introduce [a dictionary argument](https://w3ctag.github.io/design-principles/#prefer-dictionaries) with `position` and `html` keys (or `text` or `node` for the other two).

Pros:
- Path of least resistance, less substantial change than the other ideas

Cons:
- Is the improvement significant enough to warrant deprecating the existing position keywords?
- 1a: We tend to avoid making non-final arguments optional 

#### Option 2: Introducing new `<position>HTML()` methods

This would introduce new HTML methods like `appendHTML()`, `prependHTML()`, `beforeHTML()`, `afterHTML()`

Not a huge fan of this approach, as it increases the API surface significantly, and having different methods that do related but different things is an antipattern. However, it's the only one that doesn't involve overloading existing methods.

#### Option 3: Overload `element.append()`, `element.prepend()`, `node.before()`, `node.after()`

Since these already handle strings as text nodes, overloading wouldn't work. However, a dictionary overload with an `html` key still could. We probably want to be able to combine HTML strings with elements and text nodes, so this would still accept multiple arguments, each of which can be a dictionary.

Pros:
- All functionality to append/prepend/insert before/after lives under the same methods. 
- It allows us to insert before/after text nodes, whereas `insertAdjacent*` is not available there.
- Dictionary allows future extension
- More flexibility: it's the only solution that allows us to insert snippets of HTML, elements, and text nodes in a single call.

Cons:
- More verbose than 2, though still less than 1 (compare:  `element.insertAdjacentHTML("before", foo)` vs `element.beforeHTML(foo)` vs `element.before({html: foo})`)

#### Option 4: Single `node.insert(...content)` method to rule them all

This would basically encompass all `insertAdjacent*` PLUS functionality in a single method. 
`content` could be either a string (which would create a text node), a node, or a dictionary with the following structure:

```js
{
 html?: string,
 text?: string
 node?: string,
 [position = "end"]: "before" | "after" | "start" | "end"
}
```

The method would ideally be available on `Node` and would error if `start | end` are used on non-elements.

Pros:
- Basically what `insertAdjacent*` should have been
- Nicely readable
- Extensible

Cons:
- More verbose than some of the other solutions
- Design creates some error conditions that do not exist in the other designs: What happens if more than one of `html`, `text`, `node` is specified? Do we get all of them or do we throw?

### Anything else?

_No response_

-- 
Reply to this email directly or view it on GitHub:
https://github.com/whatwg/dom/issues/1251
You are receiving this because you are subscribed to this thread.

Message ID: <whatwg/dom/issues/1251@github.com>

Received on Saturday, 3 February 2024 19:27:39 UTC