Can I create a self-closing element with createElement?
Asked Answered
C

3

7

I'm trying to append a line of HTML before all the children of the body.

Right now I have this:

// Prepend vsr-toggle
var vsrToggle = document.createElement("div");
vsrToggle.innerHTML = "<input type='checkbox' name='sr-toggle' id='srToggle'><label for='srToggle' role='switch'>Screen reader</label>"
document.body.insertBefore(vsrToggle, pageContent);

It's working fine because the HTML is being added to the created div. However, I need to prepend this element without wrapping it in a div.

Is there a way to prepend the HTML without first creating an element? If not, can I create the input as a self-closing element and append the label to it?

Is there a better way to achieve this?

Cheers!

Chancroid answered 7/10, 2018 at 22:53 Comment(2)
Use insertBefore() to insert the <input>, then call it again to insert the <label>. Self-closing has nothing to do with this.Awfully
Possible duplicate of php dom create element but self-closingPinstripe
L
4

Use document.createDocumentFragment() to create a node, that isn't automatically added to the document. You can then add elements to this fragment and finally add it to the document.

This is a good link: Document fragment

How to use:

var fragment = document.createDocumentFragment();
fragment.innerHTML = '<input />';
document.body.appendChild(fragment);
Lignite answered 7/10, 2018 at 23:12 Comment(3)
Didn't know about this extremely useful feature, thanks for sharing!Discovery
That's where I landed... See my answer below. Isn't createRange needed for multiple elements? Otherwise, you'd have to keep calling createDocumentFragment.Chancroid
You add elements to the fragment, as needed, creating an element-tree, then finally adding the fragment to the document.Lignite
C
2

I ended up using createRange and createContextualFragment to turn the string into a node that I could prepend using insertBefore.:

// Prepend vsr-toggle
var vsrToggle = document.createRange().createContextualFragment("<input 
type='checkbox' name='sr-toggle' id='srToggle'><label for='srToggle' 
role='switch'>Screen reader</label>");
document.body.insertBefore(vsrToggle, pageContent);
Chancroid answered 7/10, 2018 at 23:9 Comment(0)
D
1

Edit: As Poul Bak showed, there is a very useful feature in the DOM API for that. Creating elements separately (instead of having them parsed as a string) allows more control over the elements added (for example you can outright attach an event listener without queryiing it from the DOM later), but for a larger amounts of elements it quickly becomes very verbose.

Create each element separately, and insert it before the body content using

document.body.insertBefore(newNode, document.body.firstChild);

const vsrToggle = document.createElement("input");
vsrToggle.name="sr-toggle";
vsrToggle.id="srToggle";
vsrToggle.type="checkbox";

const vsrToggleLabel = document.createElement("label");
vsrToggleLabel.setAttribute("for", vsrToggle.id);
vsrToggleLabel.setAttribute("role", "switch");
vsrToggleLabel.textContent = "Screen reader";

document.body.insertBefore(vsrToggle, document.body.firstChild);
document.body.insertBefore(vsrToggleLabel, document.body.firstChild);
<body>
  <h1>Body headline</h1>
  <p>Some random content</p>
</body>
Discovery answered 7/10, 2018 at 23:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.