DOM manipulation and browser APIs including element selection, events, storage, fetch, and modern Web APIs.
Manipulate the DOM and use browser APIs like fetch, storage, and events. Triggered when building interactive web apps, handling user interactions, or managing data persistence.
/plugin marketplace add pluginagentmarketplace/custom-plugin-javascript/plugin install javascript-developer-plugin@pluginagentmarketplace-javascriptThis skill inherits all available tools. When active, it can use any tool Claude has access to.
assets/config.yamlassets/dom-selectors.yamlreferences/DOM-MANIPULATION-GUIDE.mdreferences/GUIDE.mdscripts/dom-analyzer.jsscripts/helper.py// Modern (preferred)
document.querySelector('#id');
document.querySelector('.class');
document.querySelectorAll('div.item');
// Scoped
container.querySelector('.child');
// Cache references
const els = {
form: document.querySelector('#form'),
input: document.querySelector('#input'),
btn: document.querySelector('#btn')
};
// Safe text (XSS-safe)
el.textContent = userInput;
// Create elements (safest)
const div = document.createElement('div');
div.className = 'card';
div.textContent = title;
parent.appendChild(div);
// Batch updates (performance)
const fragment = document.createDocumentFragment();
items.forEach(item => {
const li = document.createElement('li');
li.textContent = item;
fragment.appendChild(li);
});
list.appendChild(fragment);
// Event delegation (best practice)
list.addEventListener('click', (e) => {
if (e.target.matches('.delete')) {
e.target.closest('li').remove();
}
});
// Options
el.addEventListener('click', handler, {
once: true, // Remove after first call
passive: true, // Never preventDefault
capture: false // Bubbling phase
});
// Cleanup with AbortController
const controller = new AbortController();
el.addEventListener('click', handler, { signal: controller.signal });
controller.abort(); // Remove listener
// LocalStorage (persistent)
localStorage.setItem('key', JSON.stringify(data));
const data = JSON.parse(localStorage.getItem('key'));
// SessionStorage (tab-only)
sessionStorage.setItem('token', value);
// Safe wrapper
const storage = {
get: (k, def = null) => {
try { return JSON.parse(localStorage.getItem(k)) ?? def; }
catch { return def; }
},
set: (k, v) => localStorage.setItem(k, JSON.stringify(v))
};
// GET
const res = await fetch('/api/data');
const data = await res.json();
// POST
await fetch('/api/data', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(data)
});
// With error handling
async function fetchJSON(url) {
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
}
// Intersection Observer (lazy loading)
const observer = new IntersectionObserver((entries) => {
entries.forEach(e => {
if (e.isIntersecting) {
e.target.src = e.target.dataset.src;
observer.unobserve(e.target);
}
});
});
document.querySelectorAll('img[data-src]').forEach(img => {
observer.observe(img);
});
// Clipboard
await navigator.clipboard.writeText(text);
// Geolocation
navigator.geolocation.getCurrentPosition(
pos => console.log(pos.coords),
err => console.error(err)
);
| Problem | Symptom | Fix |
|---|---|---|
| Element not found | null returned | Check if DOM loaded |
| Event not firing | Handler not called | Verify selector/delegation |
| XSS vulnerability | Script execution | Use textContent |
| Memory leak | Growing memory | Remove listeners |
// 1. Verify element exists
const el = document.querySelector('#id');
console.assert(el, 'Element not found');
// 2. Check event target
el.addEventListener('click', (e) => {
console.log('target:', e.target);
console.log('currentTarget:', e.currentTarget);
});
// 3. Monitor DOM changes
new MutationObserver(console.log)
.observe(el, { childList: true, subtree: true });
form.addEventListener('submit', async (e) => {
e.preventDefault();
const data = Object.fromEntries(new FormData(form));
try {
btn.disabled = true;
await submitData(data);
form.reset();
} catch (err) {
showError(err.message);
} finally {
btn.disabled = false;
}
});
const debouncedSearch = debounce(async (query) => {
const results = await search(query);
renderResults(results);
}, 300);
input.addEventListener('input', (e) => {
debouncedSearch(e.target.value);
});
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.