skills/js-and-css-optimization/SKILL.md
JavaScript data structure and CSS rendering optimization — index maps, combined iterations, Set/Map lookups, immutable sort, loop min/max, property caching, SVG wrapper animation, layout thrashing, content-visibility. Use when optimizing hot loops, data processing, DOM performance, or scroll rendering.
npx skillsauth add ihj04982/my-cursor-settings js-and-css-optimizationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Low-level JavaScript data structure patterns and CSS rendering optimizations.
Multiple .find() calls by the same key should use a Map. Build map once (O(n)), then all lookups are O(1).
Bad (O(n) per lookup → O(n×m) total):
return orders.map((order) => ({
...order,
user: users.find((u) => u.id === order.userId),
}));
Good (O(1) per lookup):
const userById = new Map(users.map((u) => [u.id, u]));
return orders.map((order) => ({
...order,
user: userById.get(order.userId),
}));
Multiple .filter() or .map() calls iterate the array multiple times. Combine into one loop.
Bad (3 iterations):
const admins = users.filter((u) => u.isAdmin);
const testers = users.filter((u) => u.isTester);
const inactive = users.filter((u) => !u.isActive);
Good (1 iteration):
const admins: User[] = [], testers: User[] = [], inactive: User[] = [];
for (const user of users) {
if (user.isAdmin) admins.push(user);
if (user.isTester) testers.push(user);
if (!user.isActive) inactive.push(user);
}
Convert arrays to Set/Map for repeated membership checks.
Bad: items.filter(item => allowedIds.includes(item.id))
Good:
const allowedIds = new Set(['a', 'b', 'c']);
items.filter(item => allowedIds.has(item.id))
.sort() mutates the array in place, breaking React's immutability model. Use .toSorted().
Bad (mutates props):
const sorted = useMemo(() => users.sort((a, b) => a.name.localeCompare(b.name)), [users])
Good:
const sorted = useMemo(() => users.toSorted((a, b) => a.name.localeCompare(b.name)), [users])
Other immutable methods: .toReversed(), .toSpliced(), .with(). For older browsers: [...items].sort().
Finding extremes needs O(n), not O(n log n) sort.
Bad:
const sorted = [...projects].sort((a, b) => b.updatedAt - a.updatedAt);
return sorted[0];
Good:
let latest = projects[0];
for (let i = 1; i < projects.length; i++) {
if (projects[i].updatedAt > latest.updatedAt) latest = projects[i];
}
return latest;
Math.min(...arr) works for small arrays but fails for arrays > ~124K items (Chrome).
Check array lengths before expensive comparison operations.
function hasChanges(current: string[], original: string[]) {
if (current.length !== original.length) return true;
const currentSorted = current.toSorted();
const originalSorted = original.toSorted();
return currentSorted.some((v, i) => v !== originalSorted[i]);
}
Cache object property lookups in hot paths.
Bad (3 lookups × N iterations):
for (let i = 0; i < arr.length; i++) { process(obj.config.settings.value); }
Good (1 lookup total):
const value = obj.config.settings.value;
const len = arr.length;
for (let i = 0; i < len; i++) { process(value); }
Many browsers lack hardware acceleration for CSS animations on SVG elements. Wrap and animate the wrapper.
Bad:
<svg className="animate-spin" width="24" height="24" viewBox="0 0 24 24">
<circle cx="12" cy="12" r="10" stroke="currentColor" />
</svg>
Good:
<div className="animate-spin">
<svg width="24" height="24" viewBox="0 0 24 24">
<circle cx="12" cy="12" r="10" stroke="currentColor" />
</svg>
</div>
Don't interleave style writes with layout reads. Batch reads and writes separately.
Bad (forces reflow between each pair):
element.style.width = '100px';
const width = element.offsetWidth; // forces reflow
element.style.height = '200px';
const height = element.offsetHeight; // forces another reflow
Good (batch writes, then read):
element.style.width = '100px';
element.style.height = '200px';
const { width, height } = element.getBoundingClientRect();
Best: use CSS classes instead of inline styles.
Reference: Layout-forcing properties
Apply content-visibility: auto to defer off-screen rendering.
.message-item {
content-visibility: auto;
contain-intrinsic-size: 0 80px;
}
For 1000 messages, browser skips layout/paint for ~990 off-screen items (10× faster initial render).
.find().includes().toSorted() (immutable)content-visibility: autodevelopment
Conduct WCAG 2.2 accessibility audits with automated testing, manual verification, and remediation guidance. Use when auditing websites for accessibility, fixing WCAG violations, or implementing accessible design patterns.
research
Generate high-entropy research (자료조사) and ideas (아이디어) using Verbalized Sampling to avoid mode collapse and maximize creativity and novelty.
development
React and Next.js performance optimization guidelines from Vercel Engineering. This skill should be used when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance patterns. Triggers on tasks involving React components, Next.js pages, data fetching, bundle optimization, or performance improvements.
documentation
Sync documentation from source-of-truth (package.json, .env.example). Generates CONTRIB.md, RUNBOOK.md. Use when updating project docs or after adding scripts/env vars.