I've built on the web for a while now. So long that when I'm writing vanilla HTML/JS, my go-to has always been .appendChild()
to add new HTML elements, and a huge series of createElement
calls along with it.
But there's actually some lesser-known convenience methods that we can use now (well, in a post-IE11 world, where all devs should be). ๐๐ I'm not arguing against your framework or components, but sometimes, you just have to write vanilla JS. ๐ฆ
One-Line Element Creation
I confess ๐
that this isn't really one line, but it's one statement:
const el = Object.assign(document.createElement('div'), {
textContent: `Your div now has text`,
className: 'and-is-classy',
});
The helper Object.assign
wasn't available in IE11.
Remove Self
This one is pretty well-known.
const el = document.getElementById('something');
el.remove(); // instead of el.parentNode.removeChild(el)
Insert Element or Text
The .append()
method can append any real elements, or it will automatically create a text node if you pass it a string. It takes any number of arguments.
el.append(document.createElement('hr'), 'I get upgraded to a text node!');
There's also .prepend()
which is the opposite of .append()
. It inserts all the elements, in-order, at the start of the element:
const heading = Object.assign(document.createElement('h2', {
textContent: 'List Of Awesome HTML Methods',
});
list.prepend(heading, `You Won't Believe How Many We Found!`);
Insert Relative To Element
Every element has methods .before()
and .after()
. These insert new HTML nodes directly adjacent to the current node. Like the methods above, they accept any number of other elements or strings.
myHeading.before(superHeading);
myHeading.after(`Here's a list of awesome stuff`, theList);
โ ๏ธ There's one caveat: in our example, if myHeading
isn't actually on the pageโit's a temporary elementโthese methods will just fail silently without throwing an Error
.
Replace Self
Rather than doing a parentNode.replaceChild
dance, we can now self-destruct an element and replace it with something new. Again, we can replace ourselves with any number of other elements or strings (even none!).
const fancyItem = Object.assign(document.createElement('strong'), {
textContent: 'fancy',
});
someFancyHeading.replaceWith('Less', fancyItem, 'heading');
someFancyHeading.replaceWith(); // although you could just use .remove ๐คท
Class Force Set
If you want to set the state of a class to a variable true or false, you can pass a second param to .classList.toggle
:
const someState = false;
theDiv.classList.toggle('foo', !someState); // forces foo on
theDev.classList.toggle('bar', someState); // forces bar off
// result e.g. <div id="theDiv" class="foo">
This is probably well-known. But if you're explicitly not supporting IE11, it's nice to be confident that this now works. ๐
Done!
What have I missed? Let me know if there any other old habits you've recently discovered you can let go of.
9 ๐
Top comments (14)
It never occurred to me to create new elements with object assign. ๐ฅ I always created the element then added properties and attributes after.
I nearly didn't include this oneโit was added last. But I've seen a few people remark on how neat it is in some of my codebases, so I'm glad to share? ๐คท
It's so useful when adding a bunch of properties to
.style
๐I made a little helper function based on your example @samthor which also handles inline styles. Thought I'd share here in case anyone else finds it useful. So the only thing else I added was handling inline style and wrapped it all into a function.
Hi Sam,
For some reasons I stumbled upon your article while googling and if I may ask, how would you write vanilla JS for this
Your input is much appreciated ;)
For a one-liner... hmm:
If you're not happy using innerHTML then it could look like this:
I keep coming back to this because I love it and am using the object assign right now, I have a little question.
Is there a way in object assign to insert children such as for instance if I want to put a x next to a image to say delete?
I don't think so, sorry. You can't assign to
.children
in this way.Thanks for your reply, I was playing with it a little bit probably when I should have been concentrating on work ๐.
You can use innerHTML though!! And I called the on click with a function so learned 2 new things yesterday about it
As a curiosity:
.remove
on<select>
elements can take an optional argument. Why?Because it's the method used to remove an option from its list. So, in this specific case,
.remove
does two different things: when called with no parameters, removes the element itself; when a index is passed, it removes the corresponding option in the list.I'd suggest the awkwardly-specified, but still quite useful methods
.insertAdjacentElement
/.insertAdjacentHTML
/.insertAdjacentText
, that originated with Internet Explorer 4 (!), and take two arguments. The first of which is a string among'beforebegin'
,'beforeend'
,'afterbegin'
and'afterend'
. Weird.But anyway, while the other two can be nicely polyfilled with other methods,
.insertAdjacentHTML
is quite unique, and can be seen as the only correct way to append a piece of HTML to an element without too much fuss or making a mess (someone saidel.innerHTML += '<b>Just kidding!</b>'
?).I've not really used the
.insertAdjacent...
methods. Good point about adding HTML thoughโI suppose the other way to do that is to create a dummy node (or fragment) and then append the content of that, but that is nice... if you're adding HTML directly.const el = Object.assign(document.createElement('div'), {
textContent:
Your div now has text
,className: 'and-is-classy',
});
This is sooooo gooood!!!
Object.assign
works wonderfully~~~I love this and will be playing with it today!!