Skip to content

Instantly share code, notes, and snippets.

@AeonFr
Last active August 7, 2018 06:29
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AeonFr/2741024955144311631e97f9e178d9b4 to your computer and use it in GitHub Desktop.
Save AeonFr/2741024955144311631e97f9e178d9b4 to your computer and use it in GitHub Desktop.
Function to create DOM elements filled with attributes and content, in one line of JavaScript. Inspired on React.createElement().
/**
* el(tag, options[, innerHTML])
* Creates an HTMLElement object
* and fills it with various attributes and properties.
* Inspired by React's `React.createElement()` function
*
* @param string tag The element's tagname, such as P, DIV, etc.
* @param object options
* An object that can contain key-value pairs of attributes such as
* "aria-label", "itemtype", "disabled", etc.
* Can also contain a "style" key that should
* be a DOMElement.style object
* (https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/style)
* Can also contain "special" properties
* that map to setters of the Element JS object, such as
* "id", "className", "contentEditable", "tabIndex" etc.
* @param string innerHTML The element's innerHTML
* (note: you can optionally, omit this argument and declare "innerHTML" inside the option's object)
* @return Element An HTML Element (object of type Element, DOMElement, DOMInputElement, etc.)
*/
function el(tag, options, innerHTML){
var el = document.createElement(tag);
Object.keys(options).forEach(function(key){
if (typeof options[key] == 'object'){
/** We deduce that if the object index is not a string,
* then it is the el.style object.
* Still, we can call this generic code that can populate
* any object with a massive assignation,
* and support other possible use-cases besides el.style
**/
Object.assign(el[key], options[key]);
} else {
/* Implement "native" setters whenever available,
* (native setters such as el.value, el.innerHTML, etc.)
* otherwise fall back to el.setAttribute()
*/
if (key in el)
el[key] = options[key];
else
el.setAttribute(key, options[key]);
}
});
if (innerHTML)
el.innerHTML = innerHTML;
return el;
}
/**
* ********************* TESTS
* */
var testWrapper = el('div', { classList: 'tests' });
document.body.appendChild(testWrapper);
testWrapper.appendChild(el('p',{ 'data-text': 'Calling el() withouth innerHTML' }));
testWrapper.appendChild(el('p',
{ style: { backgroundColor: 'red' } },
'calling el() with <code>options.style.backgroundColor = red</code>'
));
testWrapper.appendChild(el('p', {
style: { color: 'red', padding: '1rem' },
'data-order': -1,
'aria-label': 'Hello, World'
}, 'calling el() with multiple attributes and styles')
);
testWrapper.appendChild(el('p', {}, 'I was created and inserted in one line of JS!'));
testWrapper.appendChild(el('p', {
id: 'specialAttributes',
draggable: true,
contentEditable: true,
lang: 'en',
tabIndex: -1,
className: 'special-attributes special-attributes--test'
}, 'testing "special" attributes: "className" and other attributes that should map to DOMElement setters.'));
testWrapper.appendChild(el('style', {}, '.special-attributes{ color: blue }'))
testWrapper.appendChild(el('small', { style: { display: 'block', maxWidth: '30em' } },
'In the above example, the options properties map directly to DOMElement setters.'
+ ' Setting "tabindex: -1" and "class: ..." would also work,'
+ ' but the values passed would not be validated by the browser'
+ ' since they would be inserted with "getAttribute()",'
+ ' instead of using the native DOMElement.tabIndex and DOMElement.className setters.'
));
/** ------------------------------ TEST RESULTS
<div class="tests">
<p data-text="Calling el() withouth innerHTML"></p>
<p style="background-color: red;">
calling el() with <code>options.style.backgroundColor = red</code>
</p>
<p data-order="-1" aria-label="Hello, World" style="color: red; padding: 1rem;">
calling el() with multiple attributes and styles
</p>
<p>I was created and inserted in one line of JS!</p>
<p id="specialAttributes" draggable="true" contenteditable="true" lang="en" tabindex="-1" class="special-attributes special-attributes--test">
testing "special" attributes: "className" and other attributes that should map to DOMElement setters.
</p>
<style>.special-attributes{ color: blue }</style>
<small style="display: block; max-width: 30em;">
In the above example, the options properties map directly to DOMElement setters. Setting "tabindex: -1" and "class: ..." would also work, but the values passed would not be validated by the browser since they would be inserted with "getAttribute()", instead of using the native DOMElement.tabIndex and DOMElement.className setters.
</small>
</div>
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment