Encodings / Guides

encodeURIComponent

JavaScript's encodeURIComponent percent-encodes a string so it's safe to drop inside a URL — a query parameter value or a single path segment. Here's exactly what it escapes, what it leaves alone, and the handful of mistakes that still trip people up.

Try the URL encoder →

Syntax

encodeURIComponent(str)   // → percent-encoded string
decodeURIComponent(str)   // → the inverse

It takes one string and returns a new one with every "unsafe" character replaced by its UTF-8 percent-escape. It never mutates the input.

What it does and doesn't escape

encodeURIComponent leaves only these 73 characters untouched:

A-Z  a-z  0-9  -  _  .  !  ~  *  '  (  )

Everything else is percent-encoded — including the URL syntax characters that encodeURI deliberately keeps:

InputencodeURIComponent output
/%2F
?%3F
#%23
&%26
=%3D
+%2B
:%3A
@%40
space%20
(any non-ASCII)%E2%98%83 (UTF-8 bytes)

Worked examples

encodeURIComponent("hello world");   // "hello%20world"
encodeURIComponent("a/b?c=d");       // "a%2Fb%3Fc%3Dd"
encodeURIComponent("1+1=2");         // "1%2B1%3D2"
encodeURIComponent("café");          // "caf%C3%A9"

decodeURIComponent("caf%C3%A9");     // "café"

The one job it's for

Use it on a value that goes inside a URL — never on the whole URL. Encoding a value lets it contain &, =, / or ? without the URL parser mistaking them for structure:

const q = "shoes & socks";
const url = "https://example.com/search?q=" + encodeURIComponent(q);
// → https://example.com/search?q=shoes%20%26%20socks

The canonical, harder-to-misuse way is to skip manual encoding entirely:

const u = new URL("https://example.com/search");
u.searchParams.set("q", "shoes & socks");
u.toString();
// → https://example.com/search?q=shoes+%26+socks

URLSearchParams encodes a space as + (form-style) where encodeURIComponent uses %20; both decode back to a space on the server.

Common mistakes

Using it on a whole URL

Running encodeURIComponent over an entire URL escapes the :, / and ? that make it a URL, producing garbage. Use encodeURI for a full URL — or, better, build it with new URL(). See encodeURI vs encodeURIComponent.

Double-encoding

Encoding an already-encoded string turns every % into %25, so %20 becomes %2520. Encode exactly once, at the point you assemble the URL.

Expecting it to escape ! ' ( ) *

It doesn't. If a downstream consumer needs those escaped (some strict form-encoders, OAuth 1.0 signing), escape them yourself: encodeURIComponent(s).replace(/[!'()*]/g, c => '%' + c.charCodeAt(0).toString(16).toUpperCase()).

Decoding untrusted input without try/catch

decodeURIComponent throws a URIError on a lone % or a malformed escape like %ZZ. Wrap it when the input could be hostile.

Reference

FAQ

What characters does encodeURIComponent NOT escape?

Exactly these: A-Z a-z 0-9 and the eleven characters - _ . ! ~ * ' ( ). Everything else — including / ? # & = + space and all non-ASCII — is percent-encoded as one or more %XX bytes (UTF-8).

Does encodeURIComponent escape '+'?

Yes. encodeURIComponent('+') returns '%2B'. This is the opposite of encodeURI, which leaves + untouched. A literal + is only dangerous when it reaches a form-decoding server un-escaped — and encodeURIComponent prevents exactly that.

How do I reverse it?

decodeURIComponent. It's the exact inverse, except it throws a URIError on malformed escapes (a lone % or %ZZ), so wrap it in try/catch when decoding untrusted input.

encodeURIComponent or encodeURI?

encodeURIComponent, almost always. Use it for a value going inside a URL (a query parameter or a path segment). encodeURI is only for an entire, already-structured URL, and even then new URL() + URLSearchParams is safer.

Why does encodeURIComponent leave ! ' ( ) * unescaped?

Historical accident. RFC 3986 classifies them as reserved sub-delimiters, but ECMA-262's encodeURIComponent predates that and treats them as safe. They're fine in URL paths and query values; if you embed into strict form-encoded data you may need to escape them yourself.

Open the URL encoder →