July 12, 2017

How to Write Your Own JavaScript DOM Element Factory

A Basic HyperScript h() Function
edit

Recently at an interview I was asked to write a custom component from scratch with vanilla JavaScript. I thought I’d take a few minutes to write part of that code for you. It’s not as scary as it might seem at first.

There are three basic parts to any DOM element: the type of element it is, any attributes we need the element to have, and any children of the element. Knowing this, we can start to write our factory function.

const elFactory = (type, attributes, children) => {}

The first thing we need to do is create the DOM element we will eventually return. We do this with the createElement() method.

const elFactory = (type, attributes, children) => {
  const el = document.createElement(type)

  return el
}

The next thing we need to do is apply each key/value pair found in the attributes object we pass in.

const elFactory = (type, attributes, children) => {
  const el = document.createElement(type)

  for (key in attributes) {
    el.setAttribute(key, attributes[key])
  }

  return el
}

The last thing we need to do is handle children. There are two basic types of children we might run into: strings and other elements. So our function will need to handle both cases. Also, implied by the variable name children is that we might receive any number of extra arguments, so we’ll need to use the rest operator to gather up our remaining parameters into an array. That code looks like this:

const elFactory = (type, attributes, ...children) => {
  const el = document.createElement(type)

  for (key in attributes) {
    el.setAttribute(key, attributes[key])
  }

  children.forEach(child => {
    if (typeof child === 'string') {
      el.appendChild(document.createTextNode(child))
    } else {
      el.appendChild(child)
    }
  })

  return el
}

And now we have a factory function that will create DOM elements for us. We can use it like this:

const markup = elFactory(
  'div',
  { class: 'my-component' },
  elFactory('span', {}, 'Hello World!'),
  ' Thanks for reading my blog!',
)

document.body.appendChild(markup)

Which will output the following:

<div class="my-component">
  <span>Hello World!</span> Thanks for reading my blog!
</div>

In the future, I’ll discuss how we might be able to handle updates and have state available to our components. For now, this should help you if you’re ever in a similar situation.


Liked the post?
Give the author a dopamine boost with a few "beard strokes". Click the beard up to 50 times to show your appreciation.
Need help with your software problems?

My team and I are ready to help you. Hire Agathist to build your next great project or to improve one of your existing ones.

Get in touch
Kyle Shevlin's face, which is mostly a beard with eyes

Kyle Shevlin is the founder & lead software engineer of Agathist, a software development firm with a mission to build good software with good people.

Agathist
Good software by good people.
Visit https://agath.ist to learn more
Sign up for my newsletter
Let's chat some more about TypeScript, React, and frontend web development. Unsubscribe at any time.
Logo for Array.reduce()
Array.reduce()
Check out my courses!
If you enjoy my posts, you might enjoy my courses, too. Click the button to view the course or go to Courses for more information.