AI Skill Report Card
Coding Marketing Interactions
YAML--- name: coding-marketing-interactions description: Implements JavaScript interaction patterns for marketing websites. Use when building scroll animations, menus, modals, forms, and user preferences without complex engineering. ---
Coding Marketing Interactions
Quick Start15 / 15
HTML<button class="menu-toggle" data-target="nav-menu">Menu</button> <nav id="nav-menu" class="menu">...</nav> <script> // Toggle any element with data-target document.addEventListener('click', e => { const toggle = e.target.closest('[data-target]'); if (!toggle) return; const target = document.getElementById(toggle.dataset.target); target.classList.toggle('is-open'); toggle.classList.toggle('is-active'); }); </script>
Recommendation▾
Reduce verbosity in Best Practices and Common Pitfalls sections - assumes Claude needs basics explained
Workflow12 / 15
Progress:
- Set up event delegation for clicks
- Add Intersection Observer for scroll effects
- Implement smooth scrolling with offset
- Create form submission handler
- Add localStorage for preferences
- Test all interactions on mobile
Recommendation▾
The workflow checklist is too generic - make it more specific to common marketing site patterns
Examples18 / 20
Example 1: Scroll-triggered animations
CSS.fade-up { opacity: 0; transform: translateY(30px); transition: all 0.6s ease; } .fade-up.is-visible { opacity: 1; transform: translateY(0); }
JavaScript// Animate elements on scroll const observer = new IntersectionObserver(entries => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.classList.add('is-visible'); } }); }); document.querySelectorAll('.fade-up').forEach(el => observer.observe(el));
Example 2: Menu/Modal/Accordion pattern
HTML<!-- Menu --> <button data-target="mobile-menu" data-toggle="menu">Menu</button> <nav id="mobile-menu" class="menu">...</nav> <!-- Modal --> <button data-target="contact-modal" data-toggle="modal">Contact</button> <div id="contact-modal" class="modal"> <button data-close>×</button> </div> <!-- Accordion --> <div data-target="faq-1" data-toggle="accordion">Question?</div> <div id="faq-1" class="accordion-content">Answer...</div>
JavaScript// Universal toggle system document.addEventListener('click', e => { // Handle toggles const toggle = e.target.closest('[data-target]'); if (toggle) { const target = document.getElementById(toggle.dataset.target); const type = toggle.dataset.toggle; target.classList.toggle('is-open'); toggle.classList.toggle('is-active'); // Modal-specific: close on backdrop click if (type === 'modal') { document.body.classList.toggle('modal-open'); } } // Handle close buttons if (e.target.closest('[data-close]')) { const modal = e.target.closest('.modal'); modal.classList.remove('is-open'); document.body.classList.remove('modal-open'); } });
Example 3: Smooth scroll with fixed nav offset
JavaScript// Smooth scroll for anchor links document.addEventListener('click', e => { const link = e.target.closest('a[href^="#"]'); if (!link) return; e.preventDefault(); const target = document.querySelector(link.getAttribute('href')); if (!target) return; const navHeight = document.querySelector('.fixed-nav')?.offsetHeight || 0; const targetPosition = target.offsetTop - navHeight - 20; window.scrollTo({ top: targetPosition, behavior: 'smooth' }); });
Example 4: Contact form without backend
HTML<form class="contact-form" data-form="contact"> <input name="name" required> <input name="email" type="email" required> <textarea name="message" required></textarea> <button type="submit">Send Message</button> <div class="form-status"></div> </form>
JavaScript// Form handler (stores to localStorage) document.addEventListener('submit', e => { const form = e.target.closest('[data-form]'); if (!form) return; e.preventDefault(); const formData = new FormData(form); const data = Object.fromEntries(formData); // Store submission (since no backend) const submissions = JSON.parse(localStorage.getItem('form-submissions') || '[]'); submissions.push({ ...data, timestamp: new Date().toISOString() }); localStorage.setItem('form-submissions', JSON.stringify(submissions)); // Show success message form.querySelector('.form-status').innerHTML = '<p class="success">Message sent! We\'ll get back to you soon.</p>'; form.reset(); });
Example 5: User preferences
JavaScript// Theme toggle with persistence function setTheme(theme) { document.documentElement.dataset.theme = theme; localStorage.setItem('theme', theme); } // Load saved theme const savedTheme = localStorage.getItem('theme') || 'light'; setTheme(savedTheme); // Theme toggle button document.addEventListener('click', e => { if (e.target.matches('[data-theme-toggle]')) { const current = document.documentElement.dataset.theme; setTheme(current === 'light' ? 'dark' : 'light'); } });
Recommendation▾
Add one more concrete input/output example showing a complete before/after interaction result
Best Practices
CSS Classes for State
CSS/* Always use is- prefix for JavaScript-controlled states */ .menu { transform: translateX(-100%); } .menu.is-open { transform: translateX(0); } .modal { opacity: 0; pointer-events: none; } .modal.is-open { opacity: 1; pointer-events: auto; } .accordion-content { max-height: 0; overflow: hidden; } .accordion-content.is-open { max-height: 500px; }
Data Attributes for Configuration
data-target="element-id"- What to toggledata-toggle="type"- How to behave (menu, modal, accordion)data-offset="80"- Custom scroll offsetdata-delay="200"- Animation delay
Event Delegation Pattern Always use this pattern instead of individual event listeners:
JavaScriptdocument.addEventListener('click', e => { // Check what was clicked and respond accordingly if (e.target.matches('.selector')) { // Handle the click } });
Mobile-First Considerations
JavaScript// Check if user prefers reduced motion const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches; if (!prefersReducedMotion) { // Add animations } // Touch-friendly click handling document.addEventListener('touchstart', () => {}, { passive: true });
Common Pitfalls
Don't attach event listeners to elements that might not exist yet:
JavaScript// Bad document.querySelector('.button').addEventListener('click', handler); // Good - uses event delegation document.addEventListener('click', e => { if (e.target.matches('.button')) handler(e); });
Don't forget to handle edge cases:
JavaScript// Always check if elements exist const target = document.getElementById(targetId); if (!target) return; // Handle empty localStorage gracefully const data = JSON.parse(localStorage.getItem('key') || '[]');
Don't use complex state management - keep it simple:
JavaScript// Good - direct DOM manipulation element.classList.toggle('is-open'); // Avoid - unnecessary state objects const state = { isOpen: false }; // You don't need this
Don't reinvent the wheel for animations:
CSS/* Use CSS transitions, not JavaScript animations */ .element { transition: all 0.3s ease; transform: translateX(-100%); } .element.is-open { transform: translateX(0); }
Debugging Tips
JavaScript// Add this to see what's being clicked document.addEventListener('click', e => { console.log('Clicked:', e.target, 'Data attrs:', e.target.dataset); }); // Check localStorage contents console.log('All stored data:', { ...localStorage });