Claude-skill-registry dom-apis
DOM manipulation and browser APIs including element selection, events, storage, fetch, and modern Web APIs.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/dom-apis" ~/.claude/skills/majiayu000-claude-skill-registry-dom-apis && rm -rf "$T"
manifest:
skills/data/dom-apis/SKILL.mdsource content
DOM & Browser APIs Skill
Quick Reference Card
Element Selection
// 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') };
DOM Manipulation
// 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 Handling
// 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
Storage APIs
// 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)) };
Fetch API
// 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(); }
Modern Web APIs
// 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) );
Troubleshooting
Common Issues
| Problem | Symptom | Fix |
|---|---|---|
| Element not found | returned | Check if DOM loaded |
| Event not firing | Handler not called | Verify selector/delegation |
| XSS vulnerability | Script execution | Use |
| Memory leak | Growing memory | Remove listeners |
Debug Checklist
// 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 });
Production Patterns
Form Handling
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; } });
Debounced Input
const debouncedSearch = debounce(async (query) => { const results = await search(query); renderResults(results); }, 300); input.addEventListener('input', (e) => { debouncedSearch(e.target.value); });
Related
- Agent 05: DOM & Browser APIs (detailed learning)
- Skill: asynchronous: Fetch and promises
- Skill: ecosystem: Framework alternatives