JavaScript hex → string conversion is: parse hex pairs into bytes, then decode those bytes as text (UTF-8 in modern apps). Browser and Node APIs differ slightly; the mental model does not.
Test payloads quickly with Hex to String. Background: What is hexadecimal encoding?.
Node.js: Buffer (simplest)
const hex = "48656c6c6f";
const text = Buffer.from(hex, "hex").toString("utf8");
console.log(text); // Hello
// string → hex
console.log(Buffer.from("Hello", "utf8").toString("hex"));
Odd-length hex throws in modern Node. Prefer failing loudly over padding.
Browser: TypedArray + TextDecoder
function hexToBytes(hex) {
const clean = hex.replace(/\s+/g, "").replace(/^0x/i, "");
if (clean.length % 2) throw new Error("hex length must be even");
if (!/^[0-9a-fA-F]*$/.test(clean)) throw new Error("invalid hex");
const out = new Uint8Array(clean.length / 2);
for (let i = 0; i < clean.length; i += 2) {
out[i / 2] = parseInt(clean.slice(i, i + 2), 16);
}
return out;
}
function hexToString(hex, encoding = "utf-8") {
return new TextDecoder(encoding).decode(hexToBytes(hex));
}
console.log(hexToString("e4bda0e5a5bd")); // 你好
ASCII-only shortcut (limited)
function hexToAscii(hex) {
const clean = hex.replace(/\s+/g, "");
let s = "";
for (let i = 0; i < clean.length; i += 2) {
s += String.fromCharCode(parseInt(clean.slice(i, i + 2), 16));
}
return s;
}
Fine for protocol bytes in the 0–127 range. Do not use it for UTF-8 multi-byte text — use TextDecoder or Buffer instead.
Pitfalls
- Color codes are not “names”:
#FF5733converts to RGB channels, not the word “coral”. Use Hex to RGB for colors. - Odd length: reject or follow an explicit format rule — do not silently prepend
0. - Encoding: bytes from a Windows-1252 source will look wrong if you decode as UTF-8.
Round-trip check
const original = "café";
const hex = Buffer.from(original, "utf8").toString("hex");
const back = Buffer.from(hex, "hex").toString("utf8");
console.assert(original === back);
Related: String to Hex tool · Python guide · PHP guide.