Developer

JSON FORMATTER

Validate, format, and minify JSON with syntax highlighting and live error detection. Press Ctrl+Enter to format.

Status:
Top-level keys:
Depth:
Size:
Ctrl+Enter to format
Output

About JSON Formatter

JSON (JavaScript Object Notation) is the standard format for data exchange on the web today. However, minified JSON returned by APIs is often impossible for humans to read. Our JSON Formatter tool helps you instantly convert cramped, unreadable JSON into a beautiful, indented structure with syntax highlighting.

Key Features

Frequently Asked Questions

Is my data sent to your servers?

No. This tool runs entirely in your browser using JavaScript. Your data stays on your machine, making it safe for processing sensitive or private configuration files.

Why did the formatter show an error?

The JSON format is very strict. Common errors include using single quotes (JSON requires double quotes), trailing commas at the end of a list, or missing curly braces. Our validator will highlight the line to help you fix it.

What is the difference between Prettify and Minify?

Prettifying adds spaces, tabs, and newlines to make the data readable for developers. Minifying removes all unnecessary space to reduce the data size, which helps in optimizing web application performance.

Developer Reference

Core Algorithm & Standalone Script

Standalone, zero-dependency JavaScript implementation powering this tool. Free to inspect, copy, and build upon.

let lastParsed = null;

  function onInput() {
    const raw = document.getElementById('jsonInput').value.trim();
    const ta = document.getElementById('jsonInput');
    const errBar = document.getElementById('errorBar');

    if (!raw) {
      ta.className = '';
      errBar.classList.add('hidden');
      setStats(null, null, null, null);
      document.getElementById('jsonOutput').innerHTML = '';
      lastParsed = null;
      return;
    }

    try {
      lastParsed = JSON.parse(raw);
      ta.classList.remove('invalid');
      ta.classList.add('valid');
      errBar.classList.add('hidden');
      const keys = getTopLevelKeys(lastParsed);
      const depth = getDepth(lastParsed);
      const size = new TextEncoder().encode(raw).length;
      setStats('valid', keys, depth, size);
    } catch(e) {
      lastParsed = null;
      ta.classList.remove('valid');
      ta.classList.add('invalid');
      const lineInfo = extractErrorLine(e.message);
      errBar.textContent = 'SyntaxError: ' + e.message + (lineInfo ? ' (near line ' + lineInfo + ')' : '');
      errBar.classList.remove('hidden');
      setStats('invalid', '—', '—', new TextEncoder().encode(raw).length);
    }
  }

  function setStats(status, keys, depth, size) {
    const s = document.getElementById('statStatus');
    s.textContent = status || '—';
    s.className = 'stat-pill-val' + (status === 'valid' ? ' valid' : status === 'invalid' ? ' invalid' : '');
    document.getElementById('statKeys').textContent = keys !== null ? keys : '—';
    document.getElementById('statDepth').textContent = depth !== null ? depth : '—';
    document.getElementById('statSize').textContent = size !== null ? formatBytes(size) : '—';
  }

  function formatBytes(n) {
    if (n < 1024) return n + ' B';
    if (n < 1048576) return (n / 1024).toFixed(1) + ' KB';
    return (n / 1048576).toFixed(2) + ' MB';
  }

  function getTopLevelKeys(obj) {
    if (obj === null || typeof obj !== 'object') return 0;
    if (Array.isArray(obj)) return obj.length;
    return Object.keys(obj).length;
  }

  function getDepth(obj) {
    if (obj === null || typeof obj !== 'object') return 0;
    if (Array.isArray(obj)) {
      if (obj.length === 0) return 1;
      return 1 + Math.max(...obj.map(getDepth));
    }
    const vals = Object.values(obj);
    if (vals.length === 0) return 1;
    return 1 + Math.max(...vals.map(getDepth));
  }

  function extractErrorLine(msg) {
    const m = msg.match(/line (\d+)/i) || msg.match(/position (\d+)/i);
    return m ? m[1] : null;
  }

  function formatJson() {
    if (!lastParsed && document.getElementById('jsonInput').value.trim()) {
      onInput();
      return;
    }
    if (!lastParsed) return;
    const formatted = JSON.stringify(lastParsed, null, 2);
    document.getElementById('jsonOutput').innerHTML = syntaxHighlight(formatted);
  }

  function minifyJson() {
    if (!lastParsed) { onInput(); return; }
    if (!lastParsed) return;
    const minified = JSON.stringify(lastParsed);
    document.getElementById('jsonOutput').innerHTML = syntaxHighlight(minified);
  }

  function syntaxHighlight(json) {
    // Escape HTML first
    json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
    return json.replace(
      /("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?|[{}\[\],:])/g,
      function(match) {
        let cls = 'jn'; // number
        if (/^"/.test(match)) {
          if (/:$/.test(match)) {
            cls = 'jk'; // key
          } else {
            cls = 'js'; // string
          }
        } else if (/true|false|null/.test(match)) {
          cls = 'jb'; // boolean/null
        } else if (/[{}\[\]]/.test(match)) {
          cls = 'jp'; // punctuation
        } else if (match === ',' || match === ':') {
          cls = 'jp';
        }
        return '<span class="' + cls + '">' + match + '</span>';
      }
    );
  }

  function copyOutput() {
    if (!lastParsed) return;
    const text = document.getElementById('jsonOutput').textContent;
    navigator.clipboard.writeText(text).catch(() => {});
  }

  function copyOutputBtn(btn) {
    const text = document.getElementById('jsonOutput').textContent;
    if (!text) return;
    navigator.clipboard.writeText(text).catch(() => {});
    btn.textContent = 'copied!';
    btn.classList.add('copied');
    setTimeout(() => { btn.textContent = 'copy'; btn.classList.remove('copied'); }, 2000);
  }

  function clearAll() {
    document.getElementById('jsonInput').value = '';
    document.getElementById('jsonOutput').innerHTML = '';
    document.getElementById('jsonInput').className = '';
    document.getElementById('errorBar').classList.add('hidden');
    lastParsed = null;
    setStats(null, null, null, null);
  }

  // Keyboard shortcut
  document.getElementById('jsonInput').addEventListener('keydown', function(e) {
    if ((e.ctrlKey || e.metaKey) && e.key === 'Enter') {
      e.preventDefault();
      formatJson();
    }
    // Tab key insert spaces
    if (e.key === 'Tab') {
      e.preventDefault();
      const start = this.selectionStart;
      const end = this.selectionEnd;
      this.value = this.value.substring(0, start) + '  ' + this.value.substring(end);
      this.selectionStart = this.selectionEnd = start + 2;
      onInput();
    }
  });

  // Sample JSON
  const sample = `{
  "name": "toolpad.cc",
  "version": "1.0.0",
  "description": "Free utility tools",
  "tools": ["json", "base64", "regex", "color", "timestamp"],
  "open": true,
  "stats": {
    "users": 1000,
    "rating": 4.9,
    "free": true
  }
}`;
  document.getElementById('jsonInput').value = sample;
  onInput();
  formatJson();