Skip to content
Development
Agent

browser-dom-optimizations

<!-- Loaded by performance-optimization-engineer when task involves DOM, CSS, requestIdleCallback, localStorage, RegExp, or batch reads/writes -->

From plugin
vexjoy-agent
443198 skills198 agents12 commands83 hooks

Claude Code

$ npx -y skills add notque/vexjoy-agent --agent claude-code

Agent definition

browser-dom-optimizations.md

Browser DOM Optimizations Reference

<!-- Loaded by performance-optimization-engineer when task involves DOM, CSS, requestIdleCallback, localStorage, RegExp, or batch reads/writes -->

Apply these patterns in hot paths: render loops, event handlers called frequently, data processing pipelines. Skip them for code that runs once or rarely — the gains are real but small in isolation, and they compound when applied to high-frequency code.

---

Batch DOM and CSS Reads and Writes

**Impact:** MEDIUM — prevents forced synchronous layouts (layout thrashing)

Reading a layout property (`offsetWidth`, `getBoundingClientRect()`, `getComputedStyle()`) after making style changes forces the browser to synchronously reflow before returning the value. Batching all reads together and all writes together prevents this.

**Instead of:**

function layoutThrashing(element: HTMLElement) {
  element.style.width = '100px'
  const width = element.offsetWidth  // forced reflow
  element.style.height = '200px'
  const height = element.offsetHeight // forced reflow again
}

**Use:**

// Read phase first — all queries together
const rect = element.getBoundingClientRect()
const offsetWidth = element.offsetWidth

// Write phase after — all style changes together
element.style.width = '100px'
element.style.height = '200px'

Prefer CSS classes over inline styles when possible — toggling a class batches all style changes in one operation and keeps styles in the cached stylesheet:

function Box({ isHighlighted }: { isHighlighted: boolean }) {
  return (
    <div className={isHighlighted ? 'highlighted-box' : ''}>
      Content
    </div>
  )
}

Reference: [Layout-forcing operations](https://gist.github.com/paulirish/5d52fb081b3570c81e3a)

---

requestIdleCallback for Non-Urgent Work

**Impact:** MEDIUM — keeps UI responsive by deferring background tasks

Analytics, storage writes, prefetching, and lazy initialization do not need to run synchronously during user interactions. `requestIdleCallback` schedules them during browser idle periods, keeping the main thread free for rendering and input handling.

**Instead of:**

function handleSearch(query: string) {
  const results = searchItems(query)
  setResults(results)

  analytics.track('search', { query })     // blocks main thread immediately
  saveToRecentSearches(query)              // blocks main thread immediately
}

**Use:**

function handleSearch(query: string) {
  const results = searchItems(query)
  setResults(results)

  requestIdleCallback(() => analytics.track('search', { query }))
  requestIdleCallback(() => saveToRecentSearches(query))
}

With timeout for work that must complete eventually:

requestIdleCallback(
  () => analytics.track('page_view', { path: location.pathname }),
  { timeout: 2000 }
)

Chunking large dataset processing:

function processLargeDataset(items: Item[]) {
  let index = 0

  function processChunk(deadline: IdleDeadline) {
    while (index < items.length && deadline.timeRemaining() > 0) {
      processItem(items[index++])
    }
    if (index < items.length) requestIdleCallback(processChunk)
  }

  requestIdleCallback(processChunk)
}

Fallback for older environments:

const scheduleIdleWork = window.requestIdleCallback ?? ((cb: () => void) => setTimeout(cb, 1))

When not to use: user-initiated actions needing immediate feedback, rendering updates the user is waiting for, time-sensitive operations.

---

Cache Storage API Calls

**Impact:** LOW-MEDIUM — reduces expensive synchronous I/O

`localStorage`, `sessionStorage`, and `document.cookie` are synchronous and hit actual storage on every call. Caching reads in memory eliminates repeated I/O for the same key within a session.

**Instead of:**

function getTheme() {
  return localStorage.getItem('theme') ?? 'light' // storage read on every call
}

**Use:**

const storageCache = new Map<string, string | null>()

function getLocalStorage(key: string) {
  if (!storageCache.has(key)) {
    storageCache.set(key, localStorage.getItem(key))
  }
  return storageCache.get(key)
}

function setLocalStorage(key: string, value: string) {
  localStorage.setItem(key, value)
  storageCache.set(key, value) // keep cache in sync
}

Cookie caching:

let cookieCache: Record<string, string> | null = null

function getCookie(name: string) {
  if (!cookieCache) {
    cookieCache = Object.fromEntries(
      document.cookie.split('; ').map(c => c.split('='))
    )
  }
  return cookieCache[name]
}

Invalidate when storage can change externally (another tab, server-set cookies):

window.addEventListener('storage', e => {
  if (e.key) storageCache.delete(e.key)
})

document.addEventListener('visibilitychange', () => {
  if (document.visibilityState === 'visible') storageCache.clear()
})

---

Hoist RegExp Compilation

**Impact:** LOW-MEDIUM — avoids recreating compiled regex on every render

`new RegExp(...)` compiles the pattern on each call. Hoisting static patterns to module scope compiles once. For dynamic patterns (where the pattern depends on props/state), `useMemo` limits compilation to when inputs change.

**Instead of:**

function Highlighter({ text, query }: Props) {
  const regex = new RegExp(`(${query})`, 'gi') // compiled every render
  const parts = text.split(regex)
  return <>{parts.map((part, i) => ...)}</>
}

**Use:**

// Static pattern — hoist to module scope
const EMAIL_REGEX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/

// Dynamic pattern — memoize on inputs
function Highlighter({ text, query }: Props) {
  const regex = useMemo(
    () => new RegExp(`(${escapeRegex(query)})`, 'gi'),
    [query]
  )
  const parts = text.split(regex)
  return <>{parts.map((part, i) => ...)}</>
}

Caution: global regex (`/g` flag) has mutable `lastIndex` state. A module-level `/g` regex shared across calls

Read more
@notque
Ships withvexjoy-agent

Essays and writing behind this toolkit live at vexjoy.com. VexJoy Agent connects plain-English requests to specialist agents, skills, and workflows. /do selects the knowledge and tools needed for your task.

44363 skills198 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
443
Star history of notque/vexjoy-agent on GitHub, a chart by star-history.com

Other agents on vexjoy-agent.

modules

modules

Agent

**Scope**: Module selection patterns, builtin vs command/shell decisions, collection modules, and version-specific module changes…

@notque@notqueInstall Agent
testing

testing

Agent

**Scope**: Molecule test scenarios, ansible-lint rules, idempotency validation, and check-mode patterns **Version range**:…

@notque@notqueInstall Agent
communication-patterns

communication-patterns

Agent

**Scope**: Failure modes in agent output style — over-reporting, self-congratulation, verbose narration, and hedging. Covers what…

@notque@notqueInstall Agent

More agents from other plugins.

a11y-architect
Auto-invoked

a11y-architect

Agent

Accessibility Architect specializing in WCAG 2.2 compliance for Web and Native platforms. Use PROACTIVELY when designing UI…

ecc12d293k
@affaan-m@affaan-mInstall Agent
analyze-pass-impact

analyze-pass-impact

Agent

Analyzes how a specific topic affects a group of compiler passes. Used by the /plan-update skill to parallelize research across…

react1d252k
@facebook@facebookInstall Agent
orchestrator

orchestrator

Agent

- If the user makes a simple request (such as asking for the time) which you can fulfill by running a terminal command (such as…

codex1d135k
@openai@openaiInstall Agent
cavecrew-builder

cavecrew-builder

Agent

Surgical 1-2 file edit. Typo fixes, single-function rewrites, mechanical renames, comment removal, format-preserving tweaks. Hard…

caveman2d119k
@juliusbrussee@juliusbrusseeInstall Agent

Questions about browser-dom-optimizations.

Which coding agents can use browser-dom-optimizations?
browser-dom-optimizations installs in Claude Code and Cursor: each loads subagents from .claude/agents, so copy the file there. Flowy's auto-invocation runs in Claude Code only.