Need help with your JSON?
Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool
Building JSON Formatter Chrome Extensions
Browsing APIs, debugging network requests, or simply viewing raw JSON data in the browser can often be challenging due to its unformatted, plain-text nature. A JSON Formatter Chrome Extension solves this by automatically detecting JSON content and presenting it in a structured, readable, and highlighted format directly within the browser window.
Building such an extension is a great way to learn about Chrome Extension development, working with web content, and basic data formatting. This article will guide you through the fundamental concepts and approaches.
Why Build a JSON Formatter Extension?
- Improved Readability: Raw JSON is hard to scan. Formatting adds indentation, line breaks, and color coding, making it much easier to understand the data structure.
- Error Detection: Syntax highlighting often breaks on invalid JSON, helping spot errors quickly.
- Navigation: Many formatters allow collapsing/expanding objects and arrays, simplifying navigation through large datasets.
- Learning Opportunity: It's a practical project to understand core Chrome Extension APIs.
Extension Fundamentals
Chrome extensions are built using web technologies (HTML, CSS, JavaScript) and run in a sandboxed environment within the browser. They interact with the browser and web pages through specific APIs. Key components include:
manifest.json
: The configuration file for your extension. It defines permissions, scripts, icons, and other metadata. This is the entry point for the browser to understand your extension.- Background Script: A script that runs in the background. It handles events, manages state, and coordinates communication between different parts of the extension. It doesn't have direct access to web page content.
- Content Script: A script injected into web pages. It can read and modify the DOM of the page the user is visiting. It runs in an isolated world but can communicate with the background script.
- Browser Action (Toolbar Icon): An icon in the browser toolbar. Can open a popup or trigger an action via the background script.
- Page Action (URL Bar Icon): An icon that appears only when the extension is relevant to the current page. Less common in Manifest V3.
- DevTools Page: Creates panels in the browser's developer tools. Useful for inspecting network requests or console output.
Manifest V3
As of 2023/2024, Chrome is transitioning from Manifest V2 to Manifest V3. V3 brings security and performance enhancements, particularly changing how background processes work (Service Workers) and networking request interception (Declarative Net Request API). For a JSON formatter, the V3 changes primarily affect background scripts and potentially how you detect/intercept JSON responses, though Content Scripts remain a primary method for modifying page content.
Basic Manifest V3 Structure (manifest.json
):
{ "manifest_version": 3, "name": "My JSON Formatter", "version": "1.0", "description": "Formats JSON in browser tabs.", "permissions": [ "activeTab", // Permission to access the current tab "scripting" // Required for running content scripts in V3 // Potentially "storage" for settings, "declarativeNetRequest" for V3 request interception ], // In V3, background is a Service Worker "background": { "service_worker": "background.js" }, // Use content scripts to modify specific pages "content_scripts": [ { "matches": ["http://*/*", "https://*/*"], // Apply to all http/https pages "js": ["content.js"] // If running in pre tags, consider "run_at": "document_end" or "document_idle" } ], "icons": { // Optional icons "16": "images/icon-16.png", "48": "images/icon-48.png", "128": "images/icon-128.png" } // Add "action" for a toolbar icon/popup // "action": { // "default_popup": "popup.html" // } }
Approaches to Building the Formatter
There are two main ways to build a JSON formatter extension:
1. Content Script Approach (Modifying Page Content)
This is the most common approach for basic formatters. A content script is injected into every page (or pages matching specific patterns) and checks if the page content looks like raw JSON. If it does, the script replaces the page's body or specific elements (like <pre>
tags) with the formatted JSON.
How it works:
- Content script runs when the page loads.
- It reads the page's content (e.g.,
document.body.innerText
). - It attempts to parse the content using
JSON.parse()
. If successful, it's likely JSON. Add checks for content type headers if possible. - If parsing succeeds, apply formatting and highlighting logic. This could involve:
- Using a pre-built JavaScript formatting library.
- Manually traversing the parsed JSON object/array and building HTML elements with appropriate classes for CSS styling.
- Replace the original page content with the generated HTML.
Pros:
- Relatively simple to implement.
- Works directly on the page content the user sees.
Cons:
- Might interfere with pages that contain large amounts of text that is *almost* JSON.
- Can be challenging to detect JSON returned via AJAX calls *after* the page loads, unless you hook into network requests (which might require background scripts and different permissions).
- Replacing the entire page body might lose other elements or context. Need careful detection.
Conceptual Content Script (content.js
):
// content.js // Function to check if content is likely JSON function isLikelyJson(text) { try { JSON.parse(text); // Basic check: must be an object or array at top level const parsed = JSON.parse(text); return typeof parsed === 'object' && parsed !== null; } catch (e) { return false; } } // Function to format and highlight JSON (Placeholder) // A real implementation would use libraries or detailed DOM manipulation function formatJson(jsonText) { try { const parsed = JSON.parse(jsonText); // Example: use JSON.stringify for pretty printing initially const prettyString = JSON.stringify(parsed, null, 2); // In a real formatter, you'd generate HTML with spans for colors, etc. // For this example, we'll just wrap in a <pre> tag. // You'd also handle click-to-collapse, etc. const formattedHtml = `<pre><code>${prettyString}</code></pre>`; // Note: Need to escape HTML special characters in prettyString // and apply syntax highlighting here. return formattedHtml; } catch (e) { console.error("Failed to format JSON:", e); return null; // Return null or original text on failure } } // Check if the page content is JSON const pageText = document.body.innerText.trim(); const contentType = document.contentType; // Check header info if available // Simple heuristic: if content type is application/json OR if the text looks like JSON if (contentType === 'application/json' || (pageText.length > 0 && isLikelyJson(pageText))) { const formattedHtml = formatJson(pageText); if (formattedHtml) { // Replace the body content with the formatted JSON // Style the body or the new pre tag document.body.innerHTML = `<html> <head> <title>Formatted JSON</title> <style> body { font-family: monospace; white-space: pre-wrap; word-wrap: break-word; padding: 10px; } /* Add styles for different JSON types (strings, numbers, booleans, null, keys) */ .json-string { color: green; } .json-number { color: blue; } .json-boolean { color: red; } .json-null { color: gray; } .json-key { color: purple; font-weight: bold; } /* Add styles for expandable objects/arrays */ </style> </head> <body> ${formattedHtml} </body> </html>`; // Stop here, no need to run other scripts or observe DOM console.log("JSON formatted by extension."); // You might need to add mutation observers if JSON is loaded dynamically // However, for simple JSON responses displayed directly, this is enough. } } else { // Content is not JSON or could not be parsed. Do nothing. } // For pages that display JSON inside <pre> tags (like some browsers do for API responses) // you could instead target those specific elements: /* document.querySelectorAll('pre').forEach(preElement => { const preText = preElement.innerText.trim(); if (isLikelyJson(preText)) { const formattedHtml = formatJson(preText); if (formattedHtml) { // Create a new element to replace the pre tag const formattedContainer = document.createElement('div'); // or pre formattedContainer.innerHTML = formattedHtml; // Copy styles or add specific class formattedContainer.style.cssText = preElement.style.cssText; // Optional: copy original styles preElement.parentNode.replaceChild(formattedContainer, preElement); console.log("JSON pre tag formatted."); } } }); */ }
2. DevTools Panel Approach (Inspecting Network)
This approach involves creating a custom panel within Chrome's Developer Tools. The extension uses the chrome.devtools.network
API to listen for network requests and responses. When a response with a Content-Type: application/json
header is detected, its body is fetched and sent to the DevTools panel for display and formatting.
How it works:
- The
manifest.json
declares adevtools_page
. - The DevTools page script (e.g.,
devtools.js
) useschrome.devtools.panels.create
to add a new panel. - This script (or a background script it communicates with) listens to
chrome.devtools.network.onRequestFinished
. - When a request finishes, check its response headers for
Content-Type: application/json
. - If it's JSON, use
request.getContent()
to get the response body. - Send this content to the DevTools panel (often involves messaging between the background/devtools script and the panel's HTML page script).
- The panel's script receives the JSON string, formats it, and displays it in the panel's UI.
Pros:
- Non-intrusive: Doesn't modify the visited web page.
- Can capture JSON from AJAX requests easily.
- Provides a dedicated UI within the DevTools.
Cons:
- More complex to set up (involves multiple scripts and communication).
- Requires the user to open DevTools to see the formatted JSON.
- Doesn't format JSON directly displayed in a browser tab (like visiting a
.json
file URL).
Manifest V3 for DevTools Approach (manifest.json
):
{ "manifest_version": 3, "name": "DevTools JSON Formatter", "version": "1.0", "description": "Formats JSON in DevTools network panel.", "permissions": [ "storage" // Example: For saving settings ], "background": { "service_worker": "background.js" // Handles communication/events }, "devtools_page": "devtools.html", // The HTML page for the DevTools panel "icons": { ... } }
Conceptual DevTools Page (devtools.html
):
<!DOCTYPE html> <html> <head> <title>JSON Formatter DevTools</title> </head> <body> <script src="devtools.js"></script> </body> </html>
Conceptual DevTools Script (devtools.js
):
// devtools.js // Create a custom panel chrome.devtools.panels.create( "JSON Formatter", // Title "images/icon-16.png", // Icon (optional) "panel.html", // HTML page for the panel UI function(panel) { // Panel is created console.log("JSON Formatter DevTools panel created"); // Example: Listen for network requests and send JSON to the panel // This might be better handled in a background script in V3 chrome.devtools.network.onRequestFinished.addListener( function(request) { // Check if the response is JSON const isJsonResponse = request.response.content.mimeType === "application/json"; if (isJsonResponse) { request.getContent(function(body) { // Send the JSON body to the panel's script // Need to establish communication between devtools.js and panel.html's script // This often involves chrome.runtime.connect or chrome.runtime.sendMessage // For simplicity, imagining the panel script can receive this directly: // panel.handleJsonContent(body); // This is conceptual! console.log("Detected JSON response, need to send to panel:", body); // A more realistic approach: // chrome.runtime.sendMessage({ // type: "JSON_RESPONSE", // json: body, // url: request.request.url // }); }); } } ); } );
Conceptual Panel HTML (panel.html
):
<!DOCTYPE html> <html> <head> <title>JSON Panel</title> <style> body { font-family: monospace; white-space: pre-wrap; word-wrap: break-word; padding: 10px; } /* Add your JSON formatting CSS here */ .json-string { color: green; } .json-number { color: blue; } .json-boolean { color: red; } .json-null { color: gray; } .json-key { color: purple; font-weight: bold; } </style> </head> <body> <h1>JSON Data</h1> <div id="jsonContent">Select a network request...</div> <script src="panel.js"></script> </body> </html>
Conceptual Panel Script (panel.js
):
// panel.js const jsonContentDiv = document.getElementById('jsonContent'); // Function to format and display JSON (Placeholder) function displayFormattedJson(jsonString) { try { const parsed = JSON.parse(jsonString); // Use JSON.stringify or your custom formatting logic const prettyString = JSON.stringify(parsed, null, 2); // In a real formatter, generate HTML with syntax highlighting and collapse/expand const formattedHtml = `<pre><code>${prettyString}</code></pre>`; // Escape HTML! jsonContentDiv.innerHTML = formattedHtml; } catch (e) { jsonContentDiv.innerText = "Error formatting JSON: " + e.message; } } // Need to receive JSON data from devtools.js or background script. // Example using chrome.runtime.onMessage (if sent from background/devtools): // chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) { // if (request.type === "JSON_RESPONSE") { // console.log("Panel received JSON for", request.url); // displayFormattedJson(request.json); // } // }); // If using port connections: // const port = chrome.runtime.connect({ name: "devtools-panel" }); // port.onMessage.addListener(function(msg) { // if (msg.type === "JSON_CONTENT") { // displayFormattedJson(msg.json); // } // });
Implementing the Formatting Logic
Whether you use the Content Script or DevTools approach, the core task is taking a JSON string, parsing it into a JavaScript object/array, and then generating HTML that represents this structure with indentation and highlighting.
You can use JSON.parse()
to parse the string safely. For formatting, you have options:
JSON.stringify(data, null, 2)
: This is the simplest way to get a pretty-printed string with 2 spaces for indentation. You can then wrap this string in a<pre>
tag and potentially apply basic CSS for different data types by searching and replacing or using regular expressions (though this can be complex and error-prone).- Manual DOM Generation: Iterate through the parsed JSON object/array. For each key-value pair (in objects) or element (in arrays), create corresponding HTML elements (e.g.,
<span>
,<div>
). Add CSS classes based on the data type (string, number, boolean, null, object, array, key). This gives you fine-grained control for styling, collapse/expand features, etc. - Third-party Libraries: Libraries exist specifically for formatting and highlighting JSON in HTML. Integrating one might simplify the formatting part, but adds external dependencies to your extension. Choose carefully and consider the library's size and compatibility.
Example: Manual Formatting Structure (Conceptual)
function buildJsonHtml(data, indentLevel = 0) { const indent = ' '.repeat(indentLevel); let html = ''; if (data === null) { return `<span class="json-null">null</span>`; } switch (typeof data) { case 'boolean': return `<span class="json-boolean">${data}</span>`; case 'number': return `<span class="json-number">${data}</span>`; case 'string': // Escape string data to prevent XSS const escapedString = data.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); return `<span class="json-string">"${escapedString}"</span>`; case 'object': if (Array.isArray(data)) { // Handle Array if (data.length === 0) return '[ ]'; // Use for non-breaking space html += '[\n'; for (let i = 0; i < data.length; i++) { html += indent + ' ' + buildJsonHtml(data[i], indentLevel + 1); if (i < data.length - 1) html += ','; html += '\n'; } html += indent + ']'; return html; } else { // Handle Object const keys = Object.keys(data); if (keys.length === 0) return '{ }'; html += '{\n'; for (let i = 0; i < keys.length; i++) { const key = keys[i]; html += indent + ' ' + `<span class="json-key">"${key}"</span>: ` + buildJsonHtml(data[key], indentLevel + 1); if (i < keys.length - 1) html += ','; html += '\n'; } html += indent + '}'; return html; } default: return `<span class="json-error">Unsupported type</span>`; } } // Example usage (after parsing jsonString): // const parsedData = JSON.parse(jsonString); // const htmlOutput = buildJsonHtml(parsedData); // document.getElementById('output').innerHTML = htmlOutput;
Adding Options and Customization
A useful extension often provides options. For a JSON formatter, this might include:
- Indentation size (2 spaces, 4 spaces, tabs).
- Color scheme for syntax highlighting.
- Whether to collapse certain nodes by default.
- Enabling/disabling the formatter on specific websites.
You can implement this using:
- An Options page: An HTML page defined in
manifest.json
where users can configure settings. - The
chrome.storage
API: Used to save user settings persistently across browser sessions.
Your content or DevTools scripts can then read settings from chrome.storage.sync
(synced across signed-in browsers) or chrome.storage.local
(local only) and apply them to the formatting logic.
Packaging and Publishing
Once your extension is ready:
- Packaging: Zip the extension's files (manifest.json, scripts, icons, HTML pages, CSS).
- Testing: Load it in Chrome via
chrome://extensions
in developer mode. Test thoroughly on various JSON outputs and regular web pages. - Publishing: You can publish your extension to the Chrome Web Store through the developer dashboard. This requires a one-time fee.
Conclusion
Building a JSON Formatter Chrome Extension is a rewarding project that provides practical experience with browser extension development, content manipulation (or DevTools API usage), and frontend formatting techniques. Whether you choose the Content Script approach for direct page formatting or the DevTools approach for network inspection, understanding the Chrome Extension lifecycle and APIs is key. Start simple, perhaps using JSON.stringify
initially, and gradually add features like syntax highlighting, collapse/expand, and user options to build a robust tool.
Need help with your JSON?
Try our JSON Formatter tool to automatically identify and fix syntax errors in your JSON. JSON Formatter tool