W3docs

JavaScript TextDecoder and TextEncoder

In this chapter, we are going to explore built-in objects such as TextDecoder and TextEncoder that will make your work in JavaScript even more productive.

Mastering the TextEncoder and TextDecoder interfaces in JavaScript is essential for handling text data efficiently, especially in applications that deal with raw binary data and various character encodings. This guide explains what these interfaces do, when you actually need them, and how to use them correctly, with runnable examples and practical gotchas.

What This Page Covers

  • What text encoding and decoding mean, and why you can't just treat bytes as characters.
  • Encoding strings to bytes with TextEncoder (UTF-8 only).
  • Decoding bytes back to strings with TextDecoder, including non-UTF-8 encodings.
  • Streaming, error handling (fatal), and a real-world example with fetch.

Introduction to Text Encoding and Decoding

A JavaScript string is a sequence of characters, but the network, the filesystem, and most binary APIs work with bytes. Text encoding transforms characters into bytes following a scheme (such as UTF-8); text decoding reverses that, turning bytes back into characters. The same string can produce different byte sequences depending on the encoding, which is why a decoder needs to know which encoding the bytes were written in.

JavaScript provides two built-in interfaces for this: TextEncoder (string → bytes) and TextDecoder (bytes → string). They appear whenever you touch raw binary data — reading a Blob, processing an ArrayBuffer, or streaming a response from the Fetch API.

Using TextEncoder in JavaScript

The TextEncoder interface in JavaScript converts text from a string into an encoded byte stream. It exclusively supports UTF-8 encoding and does not accept encoding parameters in its constructor.

Basic Text Encoding Example

To encode a string using TextEncoder, follow this simple example:

javascript— editable

This script outputs a Uint8Array showing the UTF-8 encoded version of "Hello, world!". Each number is one byte: 72 is H, 101 is e, and so on. This array is the binary data that can be transmitted over network protocols or stored for later use. Note that the constructor takes no arguments — TextEncoder only ever produces UTF-8.

Advanced Encoding Techniques

Handling Non-Standard Characters

TextEncoder handles the full Unicode range seamlessly. Multi-byte characters (Chinese letters, emoji, accented letters) expand into several bytes each — a key reason the byte length of an encoded string is usually larger than its .length:

javascript— editable

This shows that TextEncoder converts any character representable in UTF-8, including emoji and special symbols, and that you should never assume one character equals one byte.

Using TextDecoder in JavaScript

While TextEncoder converts strings to bytes, TextDecoder performs the reverse, transforming encoded byte data back into readable strings. It supports multiple encodings but defaults to UTF-8.

Basic Text Decoding Example

Here's how you can decode byte data back to a string:

javascript— editable

The argument to decode() can be a Uint8Array, any other TypedArray, an ArrayBuffer, or a DataView — anything that wraps raw bytes.

This code converts a Uint8Array back to the string "Hello, world!", illustrating the basic functionality of TextDecoder.

Decoding with Different Encodings

Example Using ISO-8859-1

Unlike TextEncoder, which is UTF-8 only, TextDecoder can read many legacy encodings. Pass the encoding label (for example "iso-8859-1", "windows-1252", or "utf-16le") to the constructor:

javascript— editable

This outputs "Hello, Monde!", showing how to handle non-UTF-8 byte streams — useful when reading files produced by older systems or non-Unicode tooling.

Best Practices for Encoding and Decoding

Ensuring Text Integrity

When encoding and decoding text, ensure that the text is correctly and completely transferred or stored. Always verify that the encoded byte data converts back to the original text without loss.

Streaming Decoding Across Chunks

A multi-byte character can be split across two chunks of data arriving over the network. Decoding each chunk independently would corrupt the boundary character. The { stream: true } option tells the decoder to hold back any incomplete trailing sequence and prepend it to the next chunk. Call decode() once at the end with no argument to flush:

javascript— editable

Without { stream: true }, that split byte sequence would each decode to replacement characters (U+FFFD) and the original would be lost.

Error Handling with fatal

By default, TextDecoder replaces invalid byte sequences with the replacement character (U+FFFD, shown as ) instead of throwing. To enforce strict validation and throw a TypeError on malformed input, pass { fatal: true }:

javascript— editable

Use fatal: true when you must reject corrupted data; keep the default (lossy) behavior when partial display is better than a crash.

Real-World Example: Decoding a Fetch Response Stream

The most common practical use of TextDecoder is reading a streamed HTTP response body byte by byte. Combined with the { stream: true } option, it safely reassembles text even when characters span chunk boundaries. The snippet below simulates a two-chunk stream so it runs anywhere:

javascript— editable

In real code you would obtain those chunks from response.body.getReader() after a fetch call, which is also how download progress tracking works.

When to Use TextEncoder and TextDecoder

  • Reading or writing the contents of a Blob or File as raw bytes.
  • Working directly with an ArrayBuffer or typed array.
  • Processing a streamed network response chunk by chunk.
  • Computing byte lengths (for Content-Length headers) where character count is not enough.

You usually do not need them for ordinary JSON or text fetched with response.json() / response.text() — the browser handles decoding there for you.

Conclusion

TextEncoder and TextDecoder are the bridge between JavaScript strings and the raw bytes used by binary APIs, the network, and the filesystem. Remember the essentials: TextEncoder is UTF-8 only and takes no options; TextDecoder supports many encodings and offers { stream: true } for chunked data and { fatal: true } for strict validation. With these in your toolkit, you can handle text correctly across any encoding and data source.

Practice

Practice
Which of the following statements are true regarding TextEncoder and TextDecoder in JavaScript?
Which of the following statements are true regarding TextEncoder and TextDecoder in JavaScript?
Was this page helpful?