Dom Inspector Tool Chrome Extension (2026)
Building a Chrome Extension DOM Inspector Tool
A DOM inspector lets you examine and manipulate the structure of any webpage in real time. While Chrome DevTools provides excellent built-in functionality, building your own extension gives you custom features, tighter workflow integration, and a deeper understanding of how browsers expose the DOM.
This guide walks through creating a functional Chrome extension that inspects DOM elements, displays their properties, and allows real-time attribute editing.
Project Structure
A Chrome extension requires a manifest file and at least one background or content script. For a DOM inspector, you’ll need:
dom-inspector/
manifest.json
popup.html
popup.js
content.js
styles.css
The manifest defines permissions and entry points. The content script runs in the context of web pages, while the popup provides the extension’s UI.
Manifest Configuration
Your manifest.json defines the extension’s capabilities:
{
"manifest_version": 3,
"name": "Custom DOM Inspector",
"version": "1.0",
"description": "Inspect and edit DOM elements with custom tools",
"permissions": ["activeTab", "scripting"],
"host_permissions": ["<all_urls>"],
"action": {
"default_popup": "popup.html",
"default_icon": "icon.png"
},
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["content.js"],
"css": ["styles.css"]
}]
}
The activeTab permission lets you interact with the currently open page. The scripting permission enables programmatic script injection when needed.
Content Script: Element Selection
The content script handles element selection on the page. It listens for messages from the popup and highlights selected elements:
// content.js
let currentElement = null;
let overlay = null;
// Create highlight overlay
function createOverlay() {
overlay = document.createElement('div');
overlay.id = 'dom-inspector-overlay';
overlay.style.cssText = `
position: absolute;
border: 2px solid #0066ff;
background: rgba(0, 102, 255, 0.1);
pointer-events: none;
z-index: 2147483647;
display: none;
`;
document.body.appendChild(overlay);
}
function highlightElement(element) {
if (!overlay) createOverlay();
const rect = element.getBoundingClientRect();
overlay.style.display = 'block';
overlay.style.left = `${rect.left + window.scrollX}px`;
overlay.style.top = `${rect.top + window.scrollY}px`;
overlay.style.width = `${rect.width}px`;
overlay.style.height = `${rect.height}px`;
currentElement = element;
}
function clearHighlight() {
if (overlay) {
overlay.style.display = 'none';
}
currentElement = null;
}
// Handle messages from popup
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === 'inspect') {
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('click', handleClick, { once: true });
} else if (request.action === 'stopInspecting') {
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('click', handleClick);
clearHighlight();
} else if (request.action === 'getElementInfo') {
if (currentElement) {
sendResponse({
tagName: currentElement.tagName,
id: currentElement.id,
className: currentElement.className,
attributes: Array.from(currentElement.attributes).map(attr => ({
name: attr.name,
value: attr.value
})),
innerHTML: currentElement.innerHTML.substring(0, 200),
textContent: currentElement.textContent.substring(0, 200)
});
}
}
return true;
});
function handleMouseMove(event) {
event.target.style.cursor = 'crosshair';
}
function handleClick(event) {
event.preventDefault();
event.stopPropagation();
highlightElement(event.target);
document.removeEventListener('mousemove', handleMouseMove);
// Notify popup
chrome.runtime.sendMessage({
action: 'elementSelected',
element: event.target.tagName
});
}
The script creates a visual overlay that follows hovered elements during inspection mode. When you click an element, it captures that element and reports back to the popup.
Popup Interface
The popup provides buttons to start inspection and displays element information:
<!-- popup.html -->
<!DOCTYPE html>
<html>
<head>
<style>
body { width: 320px; padding: 16px; font-family: system-ui, sans-serif; }
button {
width: 100%;
padding: 10px;
margin-bottom: 12px;
background: #0066ff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
button:hover { background: #0052cc; }
button.active { background: #cc0000; }
.info-section { margin-top: 12px; }
.info-label { font-weight: bold; font-size: 12px; color: #666; }
.info-value { font-size: 13px; word-break: break-all; margin-bottom: 8px; }
.tag { color: #0066ff; font-weight: bold; }
</style>
</head>
<body>
<button id="inspectBtn">Start Inspection</button>
<div id="elementInfo" style="display: none;">
<div class="info-section">
<div class="info-label">Tag</div>
<div class="info-value" id="tagName"></div>
</div>
<div class="info-section">
<div class="info-label">ID</div>
<div class="info-value" id="elementId"></div>
</div>
<div class="info-section">
<div class="info-label">Classes</div>
<div class="info-value" id="elementClasses"></div>
</div>
<div class="info-section">
<div class="info-label">Attributes</div>
<div class="info-value" id="elementAttributes"></div>
</div>
</div>
<script src="popup.js"></script>
</body>
</html>
Popup Logic
The popup script manages the inspection workflow and displays collected element data:
// popup.js
let isInspecting = false;
document.getElementById('inspectBtn').addEventListener('click', async () => {
const btn = document.getElementById('inspectBtn');
if (!isInspecting) {
// Start inspection
isInspecting = true;
btn.textContent = 'Stop Inspection';
btn.classList.add('active');
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
chrome.tabs.sendMessage(tab.id, { action: 'inspect' });
} else {
// Stop inspection
isInspecting = false;
btn.textContent = 'Start Inspection';
btn.classList.remove('active');
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
chrome.tabs.sendMessage(tab.id, { action: 'stopInspecting' });
}
});
// Listen for element selection
chrome.runtime.onMessage.addListener((request) => {
if (request.action === 'elementSelected') {
displayElementInfo();
}
});
async function displayElementInfo() {
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
chrome.tabs.sendMessage(tab.id, { action: 'getElementInfo' }, (info) => {
if (!info) return;
document.getElementById('elementInfo').style.display = 'block';
document.getElementById('tagName').textContent = `<${info.tagName}>`;
document.getElementById('elementId').textContent = info.id || '(none)';
document.getElementById('elementClasses').textContent = info.className || '(none)';
document.getElementById('elementAttributes').textContent =
info.attributes.map(a => `${a.name}="${a.value}"`).join(', ') || '(none)';
});
}
Loading Your Extension
To test the extension:
- Open Chrome and navigate to
chrome://extensions/ - Enable “Developer mode” in the top right
- Click “Load unpacked” and select your extension folder
- Navigate to any webpage and click the extension icon
- Click “Start Inspection” and hover over elements
- Click an element to see its properties
Practical Applications
A custom DOM inspector becomes valuable in several scenarios:
Automated testing verification. Inspect elements to validate that your JavaScript frameworks render the expected structure. Capture element states during test failures.
Accessibility auditing. Quick inspection reveals missing ARIA attributes, improper heading hierarchies, or unlabeled interactive elements.
Debugging dynamic content. Single-page applications often modify the DOM extensively. A custom inspector helps track exactly what changes when interactions occur.
Design system verification. Confirm that components render with expected classes and data attributes across different pages.
Extending the Inspector
Once the base works, consider adding these features:
- Attribute editing. Modify element attributes directly from the popup and see changes immediately
- CSS inspection. Display computed styles for selected elements
- DOM tree navigation. Show parent/child relationships in a collapsible tree view
- Element search. Find elements by selector or text content
- Export functionality. Copy element HTML or attributes to clipboard
The Chrome Extensions documentation provides comprehensive details on content scripts, message passing, and storage APIs. Start with the basics, then layer in features as your needs evolve.
Step-by-Step: Building the DOM Inspector
- Set up Manifest V3 with
activeTabandscriptingpermissions. - Inject the inspector panel: use
chrome.scripting.executeScriptto inject a fixed-position sidebar div when the user activates the extension. - Implement element highlighting: on
mouseover, draw a semi-transparent overlay around the hovered element with a tooltip showing tag, classes, and dimensions. - Build the element detail panel: on click, display the element’s attribute list, computed styles, and position in the DOM tree.
- Add CSS path generation: compute the full CSS selector path to the clicked element with a one-click copy button.
- Export selected elements: let users export HTML, computed styles, or XPath to a JSON file for automated test use.
Computing a Unique CSS Selector
function getCSSSelector(element) {
if (element.id) return '#' + element.id;
const parts = [];
let current = element;
while (current && current !== document.documentElement) {
let selector = current.tagName.toLowerCase();
if (current.classList.length > 0) {
selector += '.' + Array.from(current.classList).join('.');
} else {
const parent = current.parentElement;
if (parent) {
const index = Array.from(parent.children).indexOf(current) + 1;
selector += ':nth-child(' + index + ')';
}
}
parts.unshift(selector);
current = current.parentElement;
}
return parts.join(' > ');
}
Comparison with Browser DevTools
| Feature | This extension | Chrome DevTools | Firefox Inspector |
|---|---|---|---|
| Always-visible overlay | Yes | No | No |
| CSS selector copy | One-click | Manual | Manual |
| Custom export formats | Yes | Limited | Limited |
| Mobile Chrome | Yes | Via remote debug | No |
Advanced: Accessibility Audit Overlay
function auditAccessibility() {
document.querySelectorAll('img:not([alt])').forEach(img => {
img.style.outline = '3px solid red';
});
document.querySelectorAll('button').forEach(btn => {
if (!btn.textContent.trim() && !btn.getAttribute('aria-label')) {
btn.style.outline = '3px solid orange';
}
});
}
Troubleshooting
Inspector not injecting on chrome:// URLs: Chrome restricts injection on chrome:// and extension pages. Show a message in the popup explaining that the inspector only works on regular web pages.
Element highlighting flicker: Throttle the mouseover handler with requestAnimationFrame to update the overlay at most once per frame.
CSS selector not unique: Fall back to XPath when document.querySelectorAll(selector).length > 1. Use document.evaluate() to compute the XPath and switch to it automatically.
Try it: Paste your error into our Error Diagnostic for an instant fix.
Related Reading
- AI Summarizer Chrome Extension: Build Your Own Text Summarization Tool
- Chrome Extension Service Worker Inspector: Complete.
- AI Calendar Assistant Chrome Extension: A Developer’s Guide
- Figma Inspector Chrome Extension Guide (2026)
- Audit Tool Chrome Extension Guide (2026)
- Mockup Screenshot Tool Chrome Extension Guide (2026)
- Screen Annotation Tool Chrome Extension Guide (2026)
- Shadow Dom Viewer Chrome Extension Guide (2026)
- Paraphrase Tool Students Chrome Extension Guide (2026)
- GraphQL Network Inspector Chrome Extension Guide (2026)
- Chrome Extension Newsletter Design Tool for Developers
Built by theluckystrike. More at zovo.one
Find the right skill → Browse 155+ skills in our Skill Finder.