I know about the disadvantages of using innerHTML. But in my situation, innerHTML looks inevitable. Either it is unnecessarily complex or it is not possible(which I don't think so...)
Here is my code:
function identifier(reg, className) {
const regex = new RegExp(reg, "gi");
const p2 = document.querySelectorAll("p");
p2.forEach((ps) => {
ps.innerHTML = ps.innerHTML.replace(
regex,
(match) => `<span class="${className}">${match}</span>`
);
});
}
identifier("[^<>]+?:", "identifier");
Is there any alternative safer way to do this without using innerHTML?
Thanks in advance!
Edit: The p element at beginning doesn't contain any other tags. It only contains text. But I want to add spans to it with the above function. 
In this I am using RegExp with replace() method to make all identifiers(eg: Name, Email) a span for styling separately. The values like John Doe doesn't get styled.
With your additional information it's relatively easy:
p2.forEach((ps) => {
// Get text of paragraph removing any HTML
const text = ps.textContent;
// Look for colon
const colon = text.indexOf(':');
// Skip if there is no colon
if (colon === -1) {
return;
}
// Delete content of paragraph
while (ps.lastChild) {
ps.removeChild(ps.lastChild);
}
// Extract texts before (and including) colon and after colon
const labelText = text.substring(0, colon + 1);
const otherText = text.substring(colon + 1);
// Create span with text before colon
const label = document.createElement('span');
label.className = className;
label.appendChild(document.createTextNode(labelText));
// Create new text node with text after colon
const otherTextNode = document.createTextNode(otherText);
// Add both as new children of the paragraph
ps.appendChild(label);
ps.appendChild(otherTextNode);
});
It is of course longer than using innerHTML, because we are basically rewriting what the regular expression and the HTML parser for the browser is doing.