# Skill: Frontend JavaScript

Skill ID: `frontend-javascript`

Rules
- Vanilla ES6+ only; no React/Vue/Angular in runtime scripts.
- Entry points can use IIFE; reusable code as ES modules.
- Use dynamic `import()` for lazy features.
- Use descriptive globals with plugin prefix.
- Never render user/API data with unsafe `innerHTML`; use `textContent`.
- If trusted HTML is required, sanitize via controlled parser flow before insertion.
- Include nonce in authenticated requests (`X-WP-Nonce` or payload).
- Use `credentials: 'same-origin'` for authenticated fetch.
- Use event delegation; avoid inline handlers.
- Localize user-facing text with WP i18n helpers.
- Handle nonce expiry/auth errors with deterministic UI fallback.
- Check element existence before DOM reads/writes.
- Use shared API client naming (`API.delete()`, no deprecated aliases).
- Use `API.delete()`, not `api.del()`.
- `api.del()` is forbidden.
- Ensure script module mode where required (`type="module"` path).

Accessibility
- Enter/Space support for custom controls.
- Modal focus trap and focus restore on close.
- `aria-live` announcements for dynamic updates.
- Field errors linked via `aria-describedby` and `aria-invalid`.
- Escape closes modals and returns focus.

Mistakes to avoid
| Mistake | Fix |
|---|---|
| Missing nonce/header | Include nonce in every authenticated request |
| Missing `credentials: 'same-origin'` | Add credentials for authenticated fetch |
| Unsafe `innerHTML` | Use `textContent` or sanitized trusted template |
| Hardcoded JS strings | Use i18n wrappers |
| No keyboard handlers | Add Enter/Space handlers |
| No modal focus restore | Restore focus to trigger element |
| `api.del()` usage | Use `API.delete()` |
| Missing `type="module"` handling | Enqueue script as module where required |
| Direct DOM access without checks | Guard element lookups |
| Inline ad hoc notices | Use shared Toast/status component |
| Missing user feedback on action | Return/render success or error consistently |
