I agree about the nuisance of creating DOM elements. innerHTML is OK if you’re doing static content, but for anything that needs to be dynamic (untrusted input, event handlers, etc.) I have a little tiny helper library that I carry around in my head and write into projects that need it:
const $T = text => document.createTextNode(text)
function $E(tag, props, kids) {
const elem = document.createElement(tag)
for (const k in props) {
elem[k] = props[k]
}
for (const kid of kids) {
elem.appendChild(kid)
}
return elem
}
(Add flourishes as necessary for things like optional arguments and allowing falsey kids.)
This isn’t as nice as JSX, but it makes a reasonably ergonomic API for quick little projects. Here’s what the example in the article would look like (admittedly it’s a bit easier to follow with syntax highlighting):
const button = $E('button', {}, [
$E('i', {className: 'icon-lightbulb'}, []),
$T('I learned something!'),
$E('object', {data: '/confetti.svg', width: 30, height: 30}, []),
]);
This isn’t as nice as JSX, but it makes a reasonably ergonomic API for quick little projects. Here’s what the example in the article would look like (admittedly it’s a bit easier to follow with syntax highlighting):