Skip to content

Instantly share code, notes, and snippets.

@davidgilbertson
Created January 1, 2017 11:11
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save davidgilbertson/c9ff092236c695dfe8c57d23f7a1a0de to your computer and use it in GitHub Desktop.
Save davidgilbertson/c9ff092236c695dfe8c57d23f7a1a0de to your computer and use it in GitHub Desktop.
const attributeExceptions = [
`role`,
];
function appendText(el, text) {
const textNode = document.createTextNode(text);
el.appendChild(textNode);
}
function appendArray(el, children) {
children.forEach((child) => {
if (Array.isArray(child)) {
appendArray(el, child);
} else if (child instanceof window.Element) {
el.appendChild(child);
} else if (typeof child === `string`) {
appendText(el, child);
}
});
}
function setStyles(el, styles) {
if (!styles) {
el.removeAttribute(`styles`);
return;
}
Object.keys(styles).forEach((styleName) => {
if (styleName in el.style) {
el.style[styleName] = styles[styleName]; // eslint-disable-line no-param-reassign
} else {
console.warn(`${styleName} is not a valid style for a <${el.tagName.toLowerCase()}>`);
}
});
}
function makeElement(type, textOrPropsOrChild, ...otherChildren) {
const el = document.createElement(type);
if (Array.isArray(textOrPropsOrChild)) {
appendArray(el, textOrPropsOrChild);
} else if (textOrPropsOrChild instanceof window.Element) {
el.appendChild(textOrPropsOrChild);
} else if (typeof textOrPropsOrChild === `string`) {
appendText(el, textOrPropsOrChild);
} else if (typeof textOrPropsOrChild === `object`) {
Object.keys(textOrPropsOrChild).forEach((propName) => {
if (propName in el || attributeExceptions.includes(propName)) {
const value = textOrPropsOrChild[propName];
if (propName === `style`) {
setStyles(el, value);
} else if (value) {
el[propName] = value;
}
} else {
console.warn(`${propName} is not a valid property of a <${type}>`);
}
});
}
if (otherChildren) appendArray(el, otherChildren);
return el;
}
const a = (...args) => makeElement(`a`, ...args);
const button = (...args) => makeElement(`button`, ...args);
const div = (...args) => makeElement(`div`, ...args);
const h1 = (...args) => makeElement(`h1`, ...args);
const header = (...args) => makeElement(`header`, ...args);
const p = (...args) => makeElement(`p`, ...args);
const span = (...args) => makeElement(`span`, ...args);
@j-f1
Copy link

j-f1 commented Feb 22, 2018

You can simplify your appendArray function:

function appendArray(el, children) {
  children.forEach((child) => {
    if (Array.isArray(child)) {
      appendArray(el, child);
    } else if (child instanceof window.Element || typeof child === `string`) {
      el.append(child);
    }
  });
}

function makeElement(type, textOrPropsOrChild, ...otherChildren) {
  const el = document.createElement(type);

  if (Array.isArray(textOrPropsOrChild)) {
    appendArray(el, textOrPropsOrChild);
  } else if (textOrPropsOrChild instanceof window.Element || typeof textOrPropsOrChild === `string`) {
    el.append(textOrPropsOrChild);
  } else if (typeof textOrPropsOrChild === `object`) {
    // snip
  }

  if (otherChildren) appendArray(el, otherChildren);

  return el;
}

Then remove appendText, which does the same thing as append if you pass it a string.

You do lose IE + Edge support, though 🤷‍♂️

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment