Reorder columns in an HTML form
@demrks please take a look at the code below. It's a result of multiple refactoring iterations.

While the original code does the job, I find it very hard to read. Hopefully, you agree that the improved version reads better, even though there's very little new in it. Many developers including myself believe that readability is a super important aspect of coding because it directly affects complexity, and thus correctness of the code.

Here's the list of techniques I applied (in order of importance as I understand things):



Naming

Name things properly and do not abbreviate words. createNewRowElementAndInsertIntoForm(...) is definitely not a short name, but it's describing what it does with 100% precision.

Similarly, original elCol transformed into columnElement. It may be funny, but first seeing elCol I thought I'm reading code in Spanish. :)

Please never never never use the i, j, c, and similar. They are absolutely meaningless. Yes, the other dev "may understand" it, but you don't want anyone to guess what the code does. Spell things out, in most of the modern editors it's a matter of hitting &lt;F2&gt;.

Temporary variables constants

Do not hesitate to introduce reusable temporary constants with descriptive names. They make cryptic conditions if (order[i]) or if (!elRows[i]) relay the intent of the writer.

Avoid branching when possible, or minimize its "scope"

An unnecessary if-then-else for processing array/non-array orders may be generalized, if we normalize the array first.

Was:

if (!Array.isArray(order[i])) {
  moveColumn(elForm, elRows[i], order[i]);
} else {
  for (j = order[i].length - 1; j &gt;= 0; j--) {
    moveColumn(elForm, elRows[i], order[i][j]);
  };
}


Became (longer because of the name, but the branching is almost eliminated by a ternary operator that cleans the input):

const normalizerRowPrescribedOrder =
  Array.isArray(rowPrescribedOrder) ? rowPrescribedOrder : [rowPrescribedOrder];

for (let columnIndex = normalizerRowPrescribedOrder.length - 1; columnIndex &gt;= 0; columnIndex--) {
  findColumnByNameAndMoveToBeginningOfRow(formElement, currentRowElement, normalizerRowPrescribedOrder[columnIndex]);
};


"Newspaper"

Make code read top to bottom aka newspaper style (reorder() is the entry point which invokes createNewRowElementAndInsertIntoForm(), therefore reorder() should go first). Forcing the reader to jump around the code is distracting from the act of active reading, therefore leading to avoidable complications.



Result

const form = (() =&gt; {
  const columnClassName = 'formCol';
  const rowClassName = 'formRow';
  const clearClassName = 'clear';

  function reorderForm(formElement, prescribedOrder) {
    const rowElementList = formElement.querySelectorAll(`.${rowClassName}`);
    const maxRowLength = Math.max(rowElementList.length, prescribedOrder.length);

    for (let rowIndex = 0; rowIndex &lt; maxRowLength; rowIndex++) {
      const currentRowElement = rowElementList[rowIndex] || createNewRowElementAndInsertIntoForm(formElement);

      const rowPrescribedOrder = prescribedOrder[rowIndex];
      if (!rowPrescribedOrder) {
        const columnElement = currentRowElement.querySelector(`.${columnClassName}`);
        if (!columnElement) {
          removeRowElement(currentRowElement);
        }
      } else {
        const normalizedRowPrescribedOrder = Array.isArray(rowPrescribedOrder) ? rowPrescribedOrder : [rowPrescribedOrder];
        for (let columnIndex = normalizedRowPrescribedOrder.length - 1; columnIndex &gt;= 0; columnIndex--) {
          findColumnByNameAndMoveToBeginningOfRow(formElement, currentRowElement, normalizedRowPrescribedOrder[columnIndex]);
        };
      }
    }
  }

  function createNewRowElementAndInsertIntoForm(formElement) {
    const rowElement = document.createElement('div');
    rowElement.className = rowClassName;

    const clearElement = document.createElement('div');
    clearElement.className = clearClassName;

    rowElement.appendChild(clearElement);

    formElement.insertAdjacentElement('beforeEnd', rowElement);

    return rowElement;
  }

  function findColumnByNameAndMoveToBeginningOfRow(formElement, rowElement, columnName) {
    const columnElement = formElement.querySelector(`.${columnClassName}[data-id='${columnName}']`);
    rowElement.insertAdjacentElement('afterbegin', columnElement);
  }

  function removeRowElement(rowElement) {
    rowElement.parentNode.removeChild(rowElement);
  }

  return {
    reorderForm,
    // other functions for form
  };
})();

form.reorderForm(document.querySelector('.form'), [
  ['Last', 'City'],
  'First',
  'Country',
  'Phone',
]);


P.S.

It's really nice to see how one uses native API instead of jQuery!