I want to convert a hexadecimal string like bada55
into a Uint8Array
and back again.

- 5,573
- 3
- 36
- 42
4 Answers
Vanilla JS:
const fromHexString = (hexString) =>
Uint8Array.from(hexString.match(/.{1,2}/g).map((byte) => parseInt(byte, 16)));
const toHexString = (bytes) =>
bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '');
console.log(toHexString(Uint8Array.from([0, 1, 2, 42, 100, 101, 102, 255])));
console.log(fromHexString('0001022a646566ff'));
Note: this method trusts its input. If the provided input has a length of 0, an error will be thrown. If the length of the hex-encoded buffer is not divisible by 2, the final byte will be parsed as if it were prepended with a 0
(e.g. aaa
is interpreted as aa0a
).
If the hex is potentially malformed or empty (e.g. user input), check its length and handle the error before calling this method, e.g.:
const isHex = (maybeHex) =>
maybeHex.length !== 0 && maybeHex.length % 2 === 0 && !/[^a-fA-F0-9]/u.test(maybeHex);
const missingLetter = 'abc';
if (!isHex(missingLetter)) {
console.log(`The string "${missingLetter}" is not valid hex.`)
} else {
fromHexString(missingLetter);
}
Source: the Libauth library (hexToBin method)

- 1,049
- 10
- 15
-
There seems to be an issue in this answer that I've encountered .. i.e – UchihaItachi Jan 14 '19 at 06:24
-
1The condition for throwing the error is wrong, it should be reversed to `if(missingLetter.length % 2 !== 0) {` – Andrew Koster Dec 17 '19 at 00:31
-
I get a failure in `fromHexString()` if the supplied hex string is zero-length; `match()` returns null rather than a zero-length array in this case, so the call on `map()` fails. – Michael Kay Jun 30 '20 at 10:16
-
@MichaelKay – thanks, I added a note about inputs of length 0. – Jason Dreyzehner Jul 14 '20 at 22:39
-
Beautiful `fromHexString` function :) – Xunnamius May 26 '22 at 11:13
Node.js
For JavaScript running on Node
you can do this:
const hexString = 'bada55';
const hex = Uint8Array.from(Buffer.from(hexString, 'hex'));
const backToHexString = Buffer.from(hex).toString('hex');
(source: this answer by @Teneff, shared with permission)

- 43,011
- 9
- 113
- 111
Here's a solution in native JavaScript:
var string = 'bada55';
var bytes = new Uint8Array(Math.ceil(string.length / 2));
for (var i = 0; i < bytes.length; i++) bytes[i] = parseInt(string.substr(i * 2, 2), 16);
console.log(bytes);
var convertedBack = '';
for (var i = 0; i < bytes.length; i++) {
if (bytes[i] < 16) convertedBack += '0';
convertedBack += bytes[i].toString(16);
}
console.log(convertedBack);

- 1,385
- 10
- 11
Browser (mimic NodeJS behavior acurately)
I had a need to mimic the NodeJS Buffer.from(x, 'hex')
behavior in the browser environment and This is what I came up with.
It's pretty fast when I ran it through some benchmarks.
const HEX_STRINGS = "0123456789abcdef";
const MAP_HEX = {
0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6,
7: 7, 8: 8, 9: 9, a: 10, b: 11, c: 12, d: 13,
e: 14, f: 15, A: 10, B: 11, C: 12, D: 13,
E: 14, F: 15
};
// Fast Uint8Array to hex
function toHex(bytes) {
return Array.from(bytes || [])
.map((b) => HEX_STRINGS[b >> 4] + HEX_STRINGS[b & 15])
.join("");
}
// Mimics Buffer.from(x, 'hex') logic
// Stops on first non-hex string and returns
// https://github.com/nodejs/node/blob/v14.18.1/src/string_bytes.cc#L246-L261
function fromHex(hexString) {
const bytes = new Uint8Array(Math.floor((hexString || "").length / 2));
let i;
for (i = 0; i < bytes.length; i++) {
const a = MAP_HEX[hexString[i * 2]];
const b = MAP_HEX[hexString[i * 2 + 1]];
if (a === undefined || b === undefined) {
break;
}
bytes[i] = (a << 4) | b;
}
return i === bytes.length ? bytes : bytes.slice(0, i);
}

- 3,637
- 1
- 14
- 19