DEV Community

Cover image for A createElement one-liner (with attributes and children)
Rémy F.
Rémy F.

Posted on • Edited on

A createElement one-liner (with attributes and children)

The one-liner

el = (tag, props={}, ch=[]) => ch.reduce((e,c) => (e.appendChild(c),e),Object.assign(document.createElement(tag),props))
Enter fullscreen mode Exit fullscreen mode

Usage

el('ul',{classList:['list']},[
  el('li',{innerText:'first'}),
  el('li',{innerText:'second'}),
])
Enter fullscreen mode Exit fullscreen mode

Bonus: attributes support

for when properties does not exist 'data-example'

el = (tag, props = {}, ch = [], attrs = {}) => ch.reduce((e, c) => (e.appendChild(c), e), Object.entries(attrs).reduce((e, [k, v]) => (e.setAttribute(k, v), e), Object.assign(document.createElement(tag), props)));
Enter fullscreen mode Exit fullscreen mode

Usage (with attributes)

el('ul',{classList:['list']},[
  el('li',{innerText:'first'}),
  el('li',{innerText:'second'}),
], {'data-example':42}) // ul extra attributes
Enter fullscreen mode Exit fullscreen mode

Bonus: Typing

This JSTyped version allow better warning/autocomplete and accept helpers params that createElement does not (on_, classList_, dataset ...)

/**
 * @template {keyof HTMLElementTagNameMap} T
 * @param {T} tagName
 * @param {Partial<HTMLElementTagNameMap[T]> & {
 *   on_?:{ [K in keyof HTMLElementEventMap]?: (this: HTMLElementTagNameMap[T], ev: HTMLElementEventMap[K]) => any },
 *   classList_?:string[],
 *   dataset_?:Record<string,string|undefined>,
 *   style_?:Partial<CSSStyleDeclaration>,
 *   attributes_?:Record<string,string>
 * }} props
 * @param {(Node|string)[]} children
 * @returns {HTMLElementTagNameMap[T]}
 */
export function el(tagName, { on_ = {}, classList_ = [], dataset_, style_ = {}, attributes_, ...props } = {}, children = []) {
    const e = Object.assign(document.createElement(tagName), props);
    e.append(...children);
    for (const [o, ev] of Object.entries(on_)) e.addEventListener(o, /** @type {EventListener} */(ev)); // TODO: event are not correct
    for (const d in dataset_) e.dataset[d] = dataset_[d];
    for (const c of classList_) e.classList.add(c);
    for (const a in attributes_) e.setAttribute(a, attributes_[a]);
    for (const s in style_) if (style_[s]) e.style[s] = style_[s];
    return e;
}
Enter fullscreen mode Exit fullscreen mode

Usage (typing)

el("input", { style_: { border: 'none' }, on_: { input() { alert(this.value) } } })
Enter fullscreen mode Exit fullscreen mode

Top comments (0)