The Simple Version: Basic ASCII Text
For plain ASCII text (basic English letters, numbers, common punctuation), converting to binary is a short function:
function textToBinary(str) {
return str.split('').map(char =>
char.charCodeAt(0).toString(2).padStart(8, '0')
).join(' ');
}
textToBinary('Hi'); // → "01001000 01101001"
charCodeAt(0) gets the character's numeric code, toString(2) converts that number to a binary string, and padStart(8, '0') pads it to a full 8 digits. This works correctly for standard ASCII characters, but it doesn't correctly handle characters outside that range.
The Correct Version: Full UTF-8 Support
To properly handle any character — including accented letters, non-Latin scripts, and emoji — use the built-in TextEncoder, which converts a string into its actual UTF-8 byte sequence:
function textToBinaryUTF8(str) {
const bytes = new TextEncoder().encode(str);
return Array.from(bytes).map(byte =>
byte.toString(2).padStart(8, '0')
).join(' ');
}
textToBinaryUTF8('café'); // → 5 bytes, since é needs 2 bytes in UTF-8
This version correctly reflects that some characters occupy more than one byte — a detail the simpler charCodeAt version misses.
Decoding Back to Text
Going the other direction uses the matching TextDecoder:
function binaryToText(binaryStr) {
const bytes = binaryStr.split(' ').map(bin => parseInt(bin, 2));
return new TextDecoder('utf-8').decode(new Uint8Array(bytes));
}
Why This Distinction Matters in Practice
Code using the simpler charCodeAt approach will silently produce incorrect results for any text containing emoji, accented letters, or non-Latin characters — it assumes every character fits in a single byte, which is only true within the original ASCII range. Real-world text handling generally calls for the TextEncoder/TextDecoder approach, since input is rarely guaranteed to be plain ASCII.
Want to see this conversion without writing any code?
Open Binary / Hex Converter