webdevpuneet.com

Base64 & URL-Safe Encoder/Decoder — Free HTML CSS JS Snippet

Base64 & URL-Safe Encoder/Decoder · Dev · Plain HTML, CSS & JS · Live preview

Category🛠 Dev

Copy & paste

Source Code

<div class="wrap">
  <div class="head">
    <h2>Base64 Playground</h2>
    <label class="url-toggle">
      <input type="checkbox" id="urlsafe-toggle" />
      URL-safe variant
    </label>
  </div>

  <div class="grid">
    <div class="col">
      <div class="col-label">Plain text</div>
      <textarea id="plain-input" placeholder="Type or paste text here...">Hello, World! 👋</textarea>
    </div>
    <div class="controls">
      <button class="icon-btn" id="btn-encode" title="Encode →">→</button>
      <button class="icon-btn" id="btn-decode" title="← Decode">←</button>
    </div>
    <div class="col">
      <div class="col-label">Base64</div>
      <textarea id="b64-input" placeholder="Base64 output appears here..."></textarea>
    </div>
  </div>

  <div class="row-actions">
    <button class="btn" id="btn-copy-b64">Copy Base64</button>
    <button class="btn" id="btn-copy-plain">Copy Plain Text</button>
    <span class="size-note" id="size-note"></span>
  </div>

  <div class="file-zone" id="file-zone">
    <span>Drop a file here (or click) to base64-encode it as a data URI</span>
    <input type="file" id="file-input" hidden />
  </div>
  <pre class="file-out" id="file-out"></pre>
  <div class="error" id="error-msg"></div>
</div>

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month, 7 days free), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

UTF-8-safe encode/decode via TextEncoder/TextDecoder round trip — handles emoji and non-Latin text correctly
URL-safe base64 toggle (RFC 4648 §5): swaps +/ for -_ and strips = padding
Live byte-size comparison showing exact UTF-8 byte count vs base64 character count and expansion ratio
Bidirectional: encode text to base64 or decode base64 back to text with dedicated buttons
Drag-and-drop or click-to-browse file input, encoded as a full data: URI via FileReader
Copy-to-clipboard buttons for both the plain text and base64 panels
Inline error messages for malformed base64 input instead of an uncaught exception
Entirely client-side, no network request, safe to use with sensitive tokens or snippets

About this UI Snippet

Base64 Playground — UTF-8 Safe Encode/Decode, URL-Safe Variant & File-to-Data-URI

Screenshot of the Base64 & URL-Safe Encoder/Decoder snippet rendered live

Base64 turns arbitrary binary data into a text string using only 64 printable characters, which is why it shows up everywhere text-only channels need to carry binary payloads: embedding images as data URIs in CSS, putting a token in a URL query parameter, or attaching a small file to a JSON API request. This snippet is a two-way playground: type or paste text on either side and convert it, or drop a file to see its full base64 data URI.

Why btoa() alone breaks on unicode text

The browser's native btoa() function only understands strings where every character code point fits in a single byte (Latin1). Call btoa('👋') directly and it throws InvalidCharacterError, because an emoji is a multi-byte UTF-8 sequence. utf8ToB64() works around this correctly: it first runs the input through TextEncoder().encode() to get the actual UTF-8 byte sequence as a Uint8Array, converts each byte to its character code with String.fromCharCode, concatenates that into a Latin1-safe binary string, and only then calls btoa() on the result. Decoding reverses the same three steps: atob() back to a binary string, rebuild the Uint8Array, and run it through TextDecoder('utf-8'). Skipping this byte-array round trip is the single most common bug in hand-rolled base64 tools — try the emoji in the default input and toggle back and forth to see it survive intact.

The URL-safe variant is a different alphabet, not different data

Standard base64 uses + and / in its 64-character alphabet, both of which have reserved meaning inside a URL (+ often means "space", / is a path separator). RFC 4648 §5 defines a URL-safe variant that substitutes - for + and _ for /, and conventionally strips the trailing = padding since it can always be reconstructed from the string length. The urlsafe-toggle checkbox calls toUrlSafe() (a simple character substitution plus a padding-stripping regex) on encode, and fromUrlSafe() (reverse substitution plus re-padding to a multiple of four) before decode. This is exactly what JWTs, many OAuth flows, and short-link services use under the hood — see also the JWT decoder for a real-world consumer of URL-safe base64.

Live byte-size comparison

updateSize() measures the actual UTF-8 byte length of the plain text via TextEncoder().encode(...).length (not .length on the string, which counts UTF-16 code units and would misreport multi-byte characters) and compares it against the base64 output's character count. Base64 always expands data by roughly 33% because it packs 3 bytes of input into 4 output characters — seeing that ratio update live for your own input makes the "base64 costs about 4/3 the size" rule concrete instead of abstract.

File-to-data-URI via FileReader

The drop zone accepts a dragged or clicked-and-browsed file and reads it with FileReader.readAsDataURL(), which the browser natively encodes as a data:<mime-type>;base64,<data> string — the exact syntax you'd paste into an <img src>, a CSS background-image, or embed inline in HTML/CSS to avoid an extra network request for a small icon or font.

Step by step

How to Use

  1. 1
    Type or paste text on the leftClick the → arrow (or it happens automatically for the default text) to base64-encode it into the right panel.
  2. 2
    Paste base64 on the rightClick the ← arrow to decode it back into readable text on the left. Invalid base64 shows an inline error instead of throwing.
  3. 3
    Toggle URL-safe variantCheck the box to swap + and / for - and _ and strip padding — the format used by JWTs, OAuth state parameters, and short URLs.
  4. 4
    Watch the size comparisonThe note below the buttons shows the exact byte count of your plain text versus the character count of the base64 output, updating live.
  5. 5
    Copy either valueUse "Copy Base64" or "Copy Plain Text" to grab the current value of either panel to your clipboard.
  6. 6
    Drop a file for a data URIDrag a file onto the dashed zone (or click to browse) to see its full data:mime/type;base64,... string, ready to paste into an <img> src or CSS.

Real-world uses

Common Use Cases

Debugging API payloads and auth headers
Quickly decode a Basic Auth header, an API key, or a base64-encoded request/response body copied from dev tools or logs without leaving the browser.
Inlining small images or icons as data URIs
Drop a small PNG or SVG onto the file zone to get its data: URI for embedding directly in CSS background-image or an <img> tag, saving an extra HTTP request.
Teaching how base64 and URL-safe encoding work
Toggle the URL-safe checkbox on an encoded value with + or / in it and watch the exact characters swap, making the RFC 4648 alphabet difference concrete rather than abstract.
Preparing tokens for query parameters or short links
Encode a JSON blob or identifier as URL-safe base64 before embedding it in a query string, avoiding the need to percent-encode + and / characters.
Related: JWT Decoder
Pair with the JWT Decoder & Inspector — a JWT is exactly three URL-safe base64 segments, and this playground demystifies the encoding underneath it.
Related: Unix Timestamp Converter
See the Unix Timestamp Converter for a related dev pattern worth pairing with this one.
Related: CSS Grid Generator
See the CSS Grid Generator for a related dev pattern worth pairing with this one.
Related: .env File Parser & Validator
See the .env File Parser & Validator for a related dev pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

btoa() only accepts strings where every character fits in one byte (Latin1). Emoji and many non-Latin characters are multi-byte UTF-8 sequences, so btoa() throws InvalidCharacterError on them directly. This tool first encodes the string to actual UTF-8 bytes with TextEncoder, converts each byte to a Latin1-safe character, and only then calls btoa() — the standard workaround for unicode-safe base64 in the browser.

Standard base64's alphabet includes + and /, both of which have reserved meaning inside a URL. The URL-safe variant (RFC 4648 section 5) substitutes - for + and _ for /, and conventionally omits the trailing = padding characters since they can be reconstructed from the string length alone. JWTs and many OAuth flows use this variant.

Base64 encodes every 3 bytes of input as 4 output characters, so the encoded size is always about 4/3 (roughly 33% larger) of the original byte count, regardless of what the data contains. The size-note line shows this ratio for whatever you've typed.

It reads the dropped or selected file with the browser's FileReader.readAsDataURL() method, which natively produces a data:<mime-type>;base64,<encoded-data> string — the exact format usable directly as an <img> src or a CSS background-image value.

No. Every operation uses only browser built-ins (btoa, atob, TextEncoder, TextDecoder, FileReader) running locally in the page. Nothing is uploaded or transmitted, which makes it safe to test with real tokens or private file contents.