npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

use-base64

v0.1.5

Published

React hook + helpers to encode strings to Base64 (RFC 4648) in any JS runtime.

Readme

use-base64

npm version npm downloads Playground

React hooks and helpers for Base64 (RFC 4648).
Universal: works in browsers, Node.js, and SSR environments.


✨ Features

  • Universal: Works in browsers, Node.js, and SSR environments
  • RFC 4648 compliant: Standard and URL-safe Base64 variants
  • React hooks: Encode/decode + file/image utilities
  • TypeScript: Full type safety
  • Zero dependencies
  • Lightweight & tree-shakable
  • Flexible: Configurable padding, line wrapping, Unicode normalization
  • Memoized: Hooks are optimized to avoid unnecessary recomputations

Playground

Поиграться и быстро проверить поведение можно здесь:
👉 Base64 Playground — tooling.ninja


📦 Install

npm install use-base64
# or
yarn add use-base64
# or
pnpm add use-base64

🚀 Quick Start

import { useBase64 } from "use-base64"

function MyComponent() {
  const encoded = useBase64("Hello, world!")
  return <div>{encoded}</div> // "SGVsbG8sIHdvcmxkIQ=="
}

📚 API Reference

Hooks Overview

| Hook | Use Case | Returns | |-------------------------------|--------------------------------------------------------------------------------------------|-------------------------------------------------------------------------| | useBase64 | Encode a string to Base64 (memoized). | string (Base64) | | useBase64Decode | Decode Base64 string to text or bytes. | string or Uint8Array | | useBase64DecodeBytes | Decode Base64 string directly into bytes. | Uint8Array | | useBase64DecodeSafe | Safe decode with built‑in error handling (never throws). | { data: string \| Uint8Array \| null, error?: string, isValid: boolean } | | useFileToBase64 | Convert a single File to Base64 (Data URL optionally). | { base64: string, file: File } | | useImageToBase64 | Convert image File/<img>/URL to Base64 with optional resize/format. | { base64: string, width: number, height: number, format: ImageFormat } | | useMultiFileToBase64 | Convert multiple files to Base64 in batch. | FileConversionResult[] | | useAutoFileToBase64 | Auto-detect file type (image/text/binary) and convert accordingly. | FileConversionResult[] |

Functions Overview

  • encodeBase64(input, options?) → string — Encode string.
  • encodeBase64FromBytes(bytes, options?) → string — Encode bytes.
  • decodeBase64(input, options?) → string \| Uint8Array — Decode string.
  • decodeBase64ToBytes(input) → Uint8Array — Decode to bytes.

🔠 Options & Types

Encoding Options

export type Base64Options = {
  /** Base64 variant: "standard" (+/) or "url" (-_). Default: "standard" */
  variant?: "standard" | "url"
  /** Padding behavior: "preserve" or "strip". Default: "preserve" */
  padding?: "preserve" | "strip"
  /** Line wrapping: false for no wrap, number for wrap width. Default: false */
  wrap?: false | number
  /** Unicode normalization form. Default: no normalization */
  normalize?: "NFC" | "NFD" | "NFKC" | "NFKD"
}

Decoding Options

export type DecodeOptions = {
  /** Output target. Default: "string" */
  output?: "string" | "bytes"
  /** Unicode normalization form for string output */
  normalize?: "NFC" | "NFD" | "NFKC" | "NFKD"
}

File/Image Types

export type ImageFormat = "png" | "jpeg" | "webp" | "gif" | "bmp" | "svg";
export type FileConversionResult = {
  file: File;
  base64?: string;   // Data URL or raw base64 depending on options
  error?: string;
};

🧩 Usage Examples

Encode (hook)

import { useBase64 } from "use-base64"

function BasicExample() {
  const encoded = useBase64("Hello, world!") 
  return <code>{encoded}</code> // "SGVsbG8sIHdvcmxkIQ=="
}

URL-safe / no padding / wrapping / normalization

const urlSafe = useBase64("Hello/World+Test", { variant: "url" })
const noPad = useBase64("Hello", { padding: "strip" })          // "SGVsbG8"
const wrapped = useBase64("A".repeat(100), { wrap: 64 })        // MIME-like lines
const nfc = useBase64("café", { normalize: "NFC" })

Encode (functions)

import { encodeBase64, encodeBase64FromBytes } from "use-base64"

const s = encodeBase64("Hello 🌍")                    // "SGVsbG8g8J+MjQ=="
const url = encodeBase64("Hello/World+", { variant: "url" }) // "SGVsbG8_V29ybGQr"
const bytes = new TextEncoder().encode("Hello")
const s2 = encodeBase64FromBytes(bytes)               // "SGVsbG8="

Base64 Decode Hooks Examples

useBase64Decode

React hook for Base64 decoding with automatic memoization.

Basic String Decoding

import { useBase64Decode } from "use-base64"

function BasicDecodeExample() {
  // Decode to string (default)
  const decoded = useBase64Decode("SGVsbG8sIHdvcmxkIQ==")
  return <div>{decoded}</div> // "Hello, world!"
}

Decode to Bytes

function BytesDecodeExample() {
  const bytes = useBase64Decode("SGVsbG8=", { output: "bytes" })
  
  return (
    <div>
      <div>Bytes length: {bytes.length}</div>
      <div>First byte: {bytes[0]}</div> {/* 72 (ASCII 'H') */}
    </div>
  )
}

Unicode Normalization

function UnicodeDecodeExample() {
  const encoded = "Y2Fmw6k=" // "café" encoded
  
  // Default decoding
  const normal = useBase64Decode(encoded)
  
  // With normalization
  const normalized = useBase64Decode(encoded, { normalize: "NFC" })
  
  return (
    <div>
      <div>Normal: {normal}</div>
      <div>Normalized: {normalized}</div>
    </div>
  )
}

Dynamic Input Example

import { useState } from "react"

function DynamicDecodeExample() {
  const [input, setInput] = useState("SGVsbG8sIHdvcmxkIQ==")
  const [outputType, setOutputType] = useState<"string" | "bytes">("string")
  
  const decoded = useBase64Decode(input, { output: outputType })
  
  return (
    <div>
      <input 
        value={input} 
        onChange={e => setInput(e.target.value)}
        placeholder="Enter Base64 string"
      />
      <select 
        value={outputType} 
        onChange={e => setOutputType(e.target.value as "string" | "bytes")}
      >
        <option value="string">String</option>
        <option value="bytes">Bytes</option>
      </select>
      
      <div>
        Result: {
          outputType === "string" 
            ? (decoded as string)
            : `Uint8Array(${(decoded as Uint8Array).length})`
        }
      </div>
    </div>
  )
}

useBase64DecodeBytes

Specialized hook for decoding specifically to bytes.

File Data Processing

function FileDataExample() {
  // Base64 encoded image data
  const imageData = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg=="
  
  const bytes = useBase64DecodeBytes(imageData)
  
  return (
    <div>
      <div>Image data size: {bytes.length} bytes</div>
      <div>PNG signature: {Array.from(bytes.slice(0, 8)).map(b => b.toString(16).padStart(2, '0')).join(' ')}</div>
    </div>
  )
}

Binary Data Analysis

import { useState, useMemo } from "react"

function BinaryAnalysisExample() {
  const [base64Input, setBase64Input] = useState("SGVsbG8gV29ybGQ=")
  const bytes = useBase64DecodeBytes(base64Input)
  
  const hexView = useMemo(() => Array.from(bytes)
    .map(byte => byte.toString(16).padStart(2, '0'))
    .join(' ')
    .toUpperCase(), [bytes])
  
  const asciiView = useMemo(() => Array.from(bytes)
    .map(byte => byte >= 32 && byte <= 126 ? String.fromCharCode(byte) : '.')
    .join(''), [bytes])
  
  return (
    <div>
      <input 
        value={base64Input}
        onChange={e => setBase64Input(e.target.value)}
        placeholder="Enter Base64"
      />
      
      <div style={{ fontFamily: 'monospace', marginTop: 10 }}>
        <div>Size: {bytes.length} bytes</div>
        <div>Hex: {hexView}</div>
        <div>ASCII: {asciiView}</div>
      </div>
    </div>
  )
}

Blob Creation

function BlobCreationExample() {
  const pdfData = "JVBERi0xLjQKJeLjz9MKM..." // Truncated PDF data
  const bytes = useBase64DecodeBytes(pdfData)
  
  const downloadPdf = () => {
    const blob = new Blob([bytes], { type: 'application/pdf' })
    const url = URL.createObjectURL(blob)
    const a = document.createElement('a')
    a.href = url
    a.download = 'document.pdf'
    a.click()
    URL.revokeObjectURL(url)
  }
  
  return (
    <div>
      <div>PDF size: {bytes.length} bytes</div>
      <button onClick={downloadPdf}>Download PDF</button>
    </div>
  )
}

useBase64DecodeSafe

Hook with built-in error handling for safe decoding.

Input Validation

import { useState } from "react"

function SafeDecodeExample() {
  const [input, setInput] = useState("SGVsbG8=")
  const { data, error, isValid } = useBase64DecodeSafe(input)
  
  return (
    <div>
      <input 
        value={input}
        onChange={e => setInput(e.target.value)}
        placeholder="Enter Base64 string"
        style={{ 
          borderColor: isValid ? 'green' : 'red',
          backgroundColor: isValid ? '#f0fff0' : '#fff0f0'
        }}
      />
      
      {error && (
        <div style={{ color: 'red', marginTop: 5 }}>
          Error: {error}
        </div>
      )}
      
      {isValid && (
        <div style={{ color: 'green', marginTop: 5 }}>
          Decoded: {data as string}
        </div>
      )}
    </div>
  )
}

Form Validation

import { useState, useMemo } from "react"

function FormValidationExample() {
  const [credentials, setCredentials] = useState("")
  const { data, error, isValid } = useBase64DecodeSafe(credentials)
  
  const parsedCreds = useMemo(() => {
    if (!isValid || !data) return null
    const decoded = data as string
    const [username, password] = decoded.split(':')
    return { username, password }
  }, [data, isValid])
  
  return (
    <form>
      <div>
        <label>Basic Auth Credentials (Base64):</label>
        <input 
          value={credentials}
          onChange={e => setCredentials(e.target.value)}
          placeholder="dXNlcm5hbWU6cGFzc3dvcmQ="
        />
      </div>
      
      {error && (
        <div className="error">Invalid Base64: {error}</div>
      )}
      
      {parsedCreds && (
        <div className="success">
          <div>Username: {parsedCreds.username}</div>
          <div>Password: {parsedCreds.password}</div>
        </div>
      )}
      
      <button type="submit" disabled={!isValid}>
        Submit
      </button>
    </form>
  )
}

JWT Token Parser

import { useState, useMemo } from "react"

function JWTParserExample() {
  const [token, setToken] = useState("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ")
  
  const parts = token.split('.')
  const headerResult = useBase64DecodeSafe(parts[0] || "")
  const payloadResult = useBase64DecodeSafe(parts[1] || "")
  
  const header = useMemo(() => {
    try {
      return headerResult.isValid ? JSON.parse(headerResult.data as string) : null
    } catch {
      return null
    }
  }, [headerResult])
  
  const payload = useMemo(() => {
    try {
      return payloadResult.isValid ? JSON.parse(payloadResult.data as string) : null
    } catch {
      return null
    }
  }, [payloadResult])
  
  return (
    <div>
      <textarea 
        value={token}
        onChange={e => setToken(e.target.value)}
        placeholder="Paste JWT token here"
        rows={3}
        style={{ width: '100%' }}
      />
      
      <div style={{ display: 'flex', gap: 20, marginTop: 10 }}>
        <div style={{ flex: 1 }}>
          <h3>Header</h3>
          {headerResult.error ? (
            <div style={{ color: 'red' }}>Error: {headerResult.error}</div>
          ) : (
            <pre>{JSON.stringify(header, null, 2)}</pre>
          )}
        </div>
        
        <div style={{ flex: 1 }}>
          <h3>Payload</h3>
          {payloadResult.error ? (
            <div style={{ color: 'red' }}>Error: {payloadResult.error}</div>
          ) : (
            <pre>{JSON.stringify(payload, null, 2)}</pre>
          )}
        </div>
      </div>
    </div>
  )
}

Batch Decoding with Error Handling

import { useState } from "react"

function BatchDecodeExample() {
  const [inputs, setInputs] = useState([
    "SGVsbG8=",           // Valid: "Hello"
    "V29ybGQ=",           // Valid: "World"
    "InvalidBase64!!!",   // Invalid
    "VGVzdA==",           // Valid: "Test"
  ])
  
  const results = inputs.map(input => useBase64DecodeSafe(input))
  
  const addInput = () => {
    setInputs([...inputs, ""])
  }
  
  const updateInput = (index: number, value: string) => {
    const newInputs = [...inputs]
    newInputs[index] = value
    setInputs(newInputs)
  }
  
  const removeInput = (index: number) => {
    setInputs(inputs.filter((_, i) => i !== index))
  }
  
  return (
    <div>
      <h3>Batch Base64 Decoder</h3>
      
      {inputs.map((input, index) => {
        const result = results[index]
        return (
          <div key={index} style={{ 
            display: 'flex', 
            gap: 10, 
            marginBottom: 10,
            padding: 10,
            border: `1px solid ${result.isValid ? 'green' : 'red'}`,
            borderRadius: 4
          }}>
            <input 
              value={input}
              onChange={e => updateInput(index, e.target.value)}
              placeholder="Enter Base64"
              style={{ flex: 1 }}
            />
            
            <div style={{ minWidth: 200 }}>
              {result.error ? (
                <span style={{ color: 'red' }}>❌ {result.error}</span>
              ) : (
                <span style={{ color: 'green' }}>✅ "{result.data}"</span>
              )}
            </div>
            
            <button onClick={() => removeInput(index)}>Remove</button>
          </div>
        )
      })}
      
      <button onClick={addInput}>Add Input</button>
      
      <div style={{ marginTop: 20 }}>
        <strong>Summary:</strong>
        <div>Valid: {results.filter(r => r.isValid).length}</div>
        <div>Invalid: {results.filter(r => !r.isValid).length}</div>
      </div>
    </div>
  )
}

File and Image Hooks Examples

useImageToBase64

function ImageConverterExample() {
  const { data, loading, error, convertFile, convertUrl, reset } = useImageToBase64()
  
  const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0]
    if (file) {
      convertFile(file, { 
        format: 'jpeg', 
        quality: 0.8,
        maxWidth: 800,
        maxHeight: 600
      })
    }
  }
  
  const handleUrlConvert = () => {
    convertUrl('https://example.com/image.jpg', {
      format: 'webp',
      quality: 0.9
    })
  }
  
  return (
    <div>
      <input type="file" accept="image/*" onChange={handleFileChange} />
      <button onClick={handleUrlConvert}>Convert URL Image</button>
      <button onClick={reset}>Reset</button>
      
      {loading && <div>Converting...</div>}
      {error && <div style={{ color: 'red' }}>Error: {error}</div>}
      {data && (
        <div>
          <div>Base64 length: {data.length}</div>
          <img src={data} alt="Converted" style={{ maxWidth: 200 }} />
        </div>
      )}
    </div>
  )
}

useFileToBase64

function FileConverterExample() {
  const { data, loading, error, convertFile, reset } = useFileToBase64()
  
  const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0]
    if (file) {
      convertFile(file, { includePrefix: true })
    }
  }
  
  return (
    <div>
      <input type="file" onChange={handleFileChange} />
      <button onClick={reset}>Reset</button>
      
      {loading && <div>Converting...</div>}
      {error && <div style={{ color: 'red' }}>Error: {error}</div>}
      {data && (
        <div>
          <div>Data URL ready for use:</div>
          <textarea value={data} readOnly rows={3} style={{ width: '100%' }} />
        </div>
      )}
    </div>
  )
}

useMultiFileToBase64

function MultiFileConverterExample() {
  const { files, loading, convertFiles, reset } = useMultiFileToBase64()
  
  const handleFilesChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const fileList = e.target.files
    if (fileList) {
      convertFiles(fileList, { includePrefix: false })
    }
  }
  
  return (
    <div>
      <input type="file" multiple onChange={handleFilesChange} />
      <button onClick={reset}>Reset</button>
      
      {loading && <div>Converting files...</div>}
      
      <div>
        {files.map((fileResult, index) => (
          <div key={index} style={{ 
            margin: 10, 
            padding: 10, 
            border: '1px solid #ccc',
            borderRadius: 4
          }}>
            <div><strong>{fileResult.file.name}</strong></div>
            <div>Size: {fileResult.file.size} bytes</div>
            
            {fileResult.error ? (
              <div style={{ color: 'red' }}>Error: {fileResult.error}</div>
            ) : fileResult.base64 ? (
              <div style={{ color: 'green' }}>
                ✅ Converted ({fileResult.base64.length} chars)
              </div>
            ) : (
              <div>Converting...</div>
            )}
          </div>
        ))}
      </div>
    </div>
  )
}

useAutoFileToBase64

import { useState } from "react"

function AutoFileConverterExample() {
  const [selectedFile, setSelectedFile] = useState<File | null>(null)
  const { data, loading, error } = useAutoFileToBase64(selectedFile, { 
    format: 'dataUrl' 
  })
  
  const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setSelectedFile(e.target.files?.[0] || null)
  }
  
  return (
    <div>
      <input type="file" onChange={handleFileChange} />
      
      {loading && <div>Auto-converting...</div>}
      {error && <div style={{ color: 'red' }}>Error: {error}</div>}
      {data && (
        <div>
          <div>✅ Auto-converted successfully!</div>
          {selectedFile?.type.startsWith('image/') && (
            <img src={data} alt="Preview" style={{ maxWidth: 200, marginTop: 10 }} />
          )}
        </div>
      )}
    </div>
  )
}

🔧 Standalone Function Examples

Basic String Encoding

import { encodeBase64 } from "use-base64"

// Default: standard Base64 with padding
const basic = encodeBase64("Hello, world!")
// "SGVsbG8sIHdvcmxkIQ=="

const empty = encodeBase64("")
// ""

const unicode = encodeBase64("Hello 🌍")
// "SGVsbG8g8J+MjQ=="

Variant Options

// Standard Base64 (RFC 4648 Section 4)
const standard = encodeBase64("Hello/World+", { variant: "standard" })
// "SGVsbG8vV29ybGQr"

// URL-safe Base64 (RFC 4648 Section 5)
const urlSafe = encodeBase64("Hello/World+", { variant: "url" })
// "SGVsbG8_V29ybGQr" (/ becomes _, + becomes -)

Padding Options

// Preserve padding (default)
const withPadding = encodeBase64("Hello", { padding: "preserve" })
// "SGVsbG8="

// Strip padding
const noPadding = encodeBase64("Hello", { padding: "strip" })
// "SGVsbG8"

// Different padding scenarios
const onePad = encodeBase64("Hi", { padding: "strip" })    // "SGk" (was "SGk=")
const twoPad = encodeBase64("H", { padding: "strip" })     // "SA" (was "SA==")
const noPad = encodeBase64("Hello!", { padding: "strip" }) // "SGVsbG8h" (no change)

Line Wrapping

// No wrapping (default)
const noWrap = encodeBase64("A very long string...")
// Single line output

// MIME-style wrapping at 76 characters
const mime = encodeBase64("A".repeat(100), { wrap: 76 })
// Output wrapped at 76 chars per line

// Custom wrapping
const custom = encodeBase64("A".repeat(50), { wrap: 20 })
// Output wrapped at 20 chars per line

// Disable wrapping explicitly
const explicit = encodeBase64("test", { wrap: false })
// "dGVzdA=="

Unicode Normalization

// No normalization (default)
const raw = encodeBase64("café")

// Canonical composition (NFC)
const nfc = encodeBase64("café", { normalize: "NFC" })

// Canonical decomposition (NFD) 
const nfd = encodeBase64("café", { normalize: "NFD" })

// Compatibility composition (NFKC)
const nfkc = encodeBase64("²", { normalize: "NFKC" })

// Compatibility decomposition (NFKD)
const nfkd = encodeBase64("²", { normalize: "NFKD" })

Byte Array Encoding

import { encodeBase64FromBytes } from "use-base64"

// From TextEncoder
const bytes1 = new TextEncoder().encode("Hello")
const encoded1 = encodeBase64FromBytes(bytes1)
// "SGVsbG8="

// From array
const bytes2 = new Uint8Array([72, 101, 108, 108, 111])
const encoded2 = encodeBase64FromBytes(bytes2)
// "SGVsbG8="

// With options
const bytes3 = new Uint8Array([255, 254, 253])
const encoded3 = encodeBase64FromBytes(bytes3, { 
  variant: "url", 
  padding: "strip" 
})
// URL-safe without padding

Comprehensive Example

// All options demonstrated
const comprehensive = encodeBase64("Hello/World+Data", {
  variant: "url",        // Use - and _ instead of + and /
  padding: "strip",      // Remove trailing = characters
  wrap: 16,              // Insert newline every 16 characters
  normalize: "NFC"       // Normalize Unicode to composed form
})

console.log(comprehensive)
// SGVsbG8vV29ybGQr
// RGF0YQ

🔐 Common Use Cases

JWT Token Generation

function JWTHeader() {
  const header = JSON.stringify({ alg: "HS256", typ: "JWT" })
  const encoded = useBase64(header, { variant: "url", padding: "strip" })
  return <code>{encoded}</code>
}

Data URLs

function DataURL() {
  const svg = '<svg><text>Hello</text></svg>'
  const encoded = useBase64(svg)
  return <img src={`data:image/svg+xml;base64,${encoded}`} />
}

HTTP Basic Auth

function BasicAuth() {
  const credentials = useBase64("username:password")
  // Use in Authorization header: `Basic ${credentials}`
  return <code>Authorization: Basic {credentials}</code>
}

🧰 Exports

// Main exports for the library
export { useBase64 } from "./hook"
export { encodeBase64, encodeBase64FromBytes } from "./encode"
export { decodeBase64, decodeBase64ToBytes } from "./decode"
export {
  useBase64Decode,
  useBase64DecodeBytes,
  useBase64DecodeSafe
} from "./decode-hook"
export {
  useImageToBase64,
  useFileToBase64,
  useMultiFileToBase64,
  useAutoFileToBase64
} from "./image-hook"
export {
  imageElementToBase64,
  fileToBase64,
  imageFileToBase64,
  canvasToBase64,
  imageDataToBase64,
  urlToBase64
} from "./image"

// Export types
export type { Base64Options as UseBase64Options } from "./types"
export type { DecodeOptions as UseBase64DecodeOptions } from "./types"
export type {
  ImageToBase64Options,
  FileToBase64Options,
  ImageFormat,
  UseBase64State,
  UseBase64DecodeState,
  FileConversionResult
} from "./types"

🖥️ Browser & Node Support

  • Modern Browsers: Uses TextEncoder (Chrome 38+, Firefox 19+, Safari 10.1+)
  • Node.js: Falls back to Buffer when available
  • SSR: Works in server-side rendering environments
  • Legacy: Descriptive error if neither TextEncoder nor Buffer available

⚙️ Performance

  • Chunked processing: Handles large strings efficiently (e.g., 32KB chunks)
  • Memoization: Hooks memoize results to prevent extra work
  • Zero dependencies: Minimized bundle impact
  • Tree-shakable: Import only what you need

⚖️ License

MIT