lwc-focus-management

Use when building LWCs that need to manage focus explicitly — modal dialogs, wizard flows, dynamic inserts, list updates, error summaries, and focus after async work. Covers focus restoration, focus traps, programmatic focus across shadow DOM, and patterns for announcing changes to assistive tech. Does NOT cover general LWC a11y audit (see lwc-accessibility).

Best use case

lwc-focus-management is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Use when building LWCs that need to manage focus explicitly — modal dialogs, wizard flows, dynamic inserts, list updates, error summaries, and focus after async work. Covers focus restoration, focus traps, programmatic focus across shadow DOM, and patterns for announcing changes to assistive tech. Does NOT cover general LWC a11y audit (see lwc-accessibility).

Teams using lwc-focus-management should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/lwc-focus-management/SKILL.md --create-dirs "https://raw.githubusercontent.com/PranavNagrecha/AwesomeSalesforceSkills/main/skills/lwc/lwc-focus-management/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/lwc-focus-management/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How lwc-focus-management Compares

Feature / Agentlwc-focus-managementStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Use when building LWCs that need to manage focus explicitly — modal dialogs, wizard flows, dynamic inserts, list updates, error summaries, and focus after async work. Covers focus restoration, focus traps, programmatic focus across shadow DOM, and patterns for announcing changes to assistive tech. Does NOT cover general LWC a11y audit (see lwc-accessibility).

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# LWC Focus Management

## Purpose

Deterministic patterns for LWC focus management — focus restoration, traps, shadow-DOM traversal, and assistive-tech announcements — so keyboard and screen-reader users never get stranded.

## Recommended Workflow

1. **List every state transition that should move focus.** Open, close,
   error, load-complete, row added, row removed, tab switched.
2. **For each transition, specify: focus target, restoration target, and
   announcement.** A focus target alone is not enough — you also must know
   where focus should go when the state ends.
3. **Implement focus with `element.focus()` after the DOM is stable.**
   Use `renderedCallback` or `queueMicrotask` / `setTimeout(0)` to wait for
   the render.
4. **For shadow DOM, walk explicitly.** Use `this.template.querySelector`
   inside the component; if the target lives in a child component, call a
   public `focus()` method you expose on that child.
5. **Trap focus in modals.** Use the first-and-last-tab approach or a
   small helper; return focus to the opener on close.
6. **Announce changes to assistive tech.** `aria-live`, role="status", or
   role="alert" for different urgency levels.
7. **Test keyboard-only and with a screen reader.**

## Common Patterns

### Pattern 1: Modal Focus Trap With Restore

Save the opener, trap Tab between first and last focusable elements, restore on close:

```js
import { LightningElement, api } from 'lwc';

const FOCUSABLE = 'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])';

export default class FocusTrapModal extends LightningElement {
  _opener;
  _isOpen = false;
  _focused = false;

  @api open() {
    this._opener = document.activeElement;
    this._isOpen = true;
  }

  renderedCallback() {
    if (this._isOpen && !this._focused) {
      this.template.querySelector('[data-focus="first"]')?.focus();
      this._focused = true;
    }
  }

  handleKeyDown(event) {
    if (event.key !== 'Tab' || !this._isOpen) return;
    const focusable = [...this.template.querySelectorAll(FOCUSABLE)];
    if (!focusable.length) return;
    const first = focusable[0];
    const last = focusable[focusable.length - 1];
    if (event.shiftKey && document.activeElement === first) {
      event.preventDefault();
      last.focus();
    } else if (!event.shiftKey && document.activeElement === last) {
      event.preventDefault();
      first.focus();
    }
  }

  handleClose() {
    this._isOpen = false;
    this._focused = false;
    Promise.resolve().then(() => this._opener?.focus?.());
  }
}
```

### Pattern 2: Error Summary With Field Links

Render a focusable error summary (`role="alert"`) after validation; each item focuses its field on click:

```html
<!-- errorSummary.html -->
<template>
  <template if:true={hasErrors}>
    <div role="alert" tabindex="-1" data-focus="error-summary"
         class="slds-notify slds-notify_alert slds-theme_error">
      <h2>Fix {errorCount} errors before saving</h2>
      <ul>
        <template for:each={errors} for:item="err">
          <li key={err.fieldName}>
            <a href="#" data-field={err.fieldName}
               onclick={handleErrorClick}>{err.message}</a>
          </li>
        </template>
      </ul>
    </div>
  </template>
</template>
```

```js
handleSubmit() {
  this.errors = this.validate();
  if (this.errors.length) {
    this._pendingFocus = true;   // triggers renderedCallback guard
  }
}

renderedCallback() {
  if (this._pendingFocus) {
    this._pendingFocus = false;
    this.template.querySelector('[data-focus="error-summary"]')?.focus();
  }
}

handleErrorClick(event) {
  event.preventDefault();
  const fieldName = event.currentTarget.dataset.field;
  this.template.querySelector(`[data-field-input="${fieldName}"]`)?.focus();
}
```

### Pattern 3: Async Load Complete

- After fetch resolves and list renders: move focus to the first list
  heading or a "Loaded N results" announcement region. Do NOT yank focus
  during typing.

### Pattern 4: Row Add / Remove

- Row added: focus the new row or a "row added" status region.
- Row removed: focus the next row; if none, focus the previous row; if
  none, focus the list heading.

## Shadow DOM Specifics

- `this.template.querySelector` pierces this component's shadow only.
- To focus inside a child LWC, expose a public `@api focus()` that calls
  the child's own `this.template.querySelector(...).focus()`.
- Do NOT rely on global `document.activeElement` within shadow boundaries;
  use `this.template.activeElement` where supported.

## Focus After Render

`renderedCallback` fires after each render. Guard against repeated focus
calls with a flag:

```js
renderedCallback() {
  if (this._pendingFocus) {
    this._pendingFocus = false;
    this.template.querySelector('[data-focus="primary"]')?.focus();
  }
}
```

## Testing

- Keyboard-only walk: every state transition exercised.
- Screen reader: NVDA/VoiceOver confirms the right announcement.
- Jest: spy on focus(); assert called with the expected selector.

## Anti-Patterns (see references/llm-anti-patterns.md)

- Focus calls in `connectedCallback` before render.
- `document.querySelector` reaching into another component's shadow.
- Focus trap without restore.
- Firing `focus()` on every render — keystrokes get eaten.

## Official Sources Used

- LWC Documentation — https://developer.salesforce.com/docs/platform/lwc/guide/
- Shadow DOM and LWC — https://developer.salesforce.com/docs/platform/lwc/guide/create-shadow-dom.html
- Salesforce Accessibility — https://help.salesforce.com/s/articleView?id=sf.accessibility_overview.htm
- WCAG 2.1 — Focus Visible, Focus Order — https://www.w3.org/TR/WCAG21/

Related Skills

session-management-and-timeout

8
from PranavNagrecha/AwesomeSalesforceSkills

Use this skill when configuring session timeout values, concurrent session limits, session IP locking, or logout behavior in Salesforce. Covers org-wide session settings, profile-level overrides, Connected App session policies, and Metadata API SecuritySettings deployment. NOT for OAuth token refresh flows, login IP ranges, or MFA/identity-provider configuration.

oauth-token-management

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when work depends on how Salesforce OAuth access and refresh tokens are issued, refreshed, rotated, revoked, or introspected for a Connected App or API client—including unexpected logouts, invalid_grant after refresh, or designing token incident response. NOT for choosing which OAuth grant or Connected App flow to implement (use integration/oauth-flows-and-connected-apps), Named Credential packaging (use integration/named-credentials-setup), or broad Connected App IP and PKCE policy hardening without a token-lifecycle angle (use security/connected-app-security-policies).

certificate-and-key-management

8
from PranavNagrecha/AwesomeSalesforceSkills

Use this skill when creating, uploading, or rotating certificates in Salesforce, configuring mutual TLS (mTLS) client authentication, managing the Java KeyStore for CA-signed certificates, diagnosing certificate expiry in JWT OAuth flows, or understanding which certificate types Salesforce supports and how to migrate them between orgs. NOT for Named Credential configuration (use named-credentials-setup skill), NOT for Shield Platform Encryption key management. Trigger keywords: Certificate and Key Management, self-signed certificate, CA-signed certificate, mutual TLS, mTLS, keystore, JKS, PKCS12, certificate rotation, certificate expiry, JWT certificate.

flexcard-state-management

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when designing FlexCard actions, conditional visibility, and state that must survive navigation, refresh, or parent/child card transitions. Triggers: 'flexcard state', 'flexcard conditional visibility', 'flexcard actions', 'flexcard refresh', 'child flexcard state'. NOT for raw LWC state or for OmniScript step state.

lwc-state-management

8
from PranavNagrecha/AwesomeSalesforceSkills

Share state across LWCs using pub/sub, Lightning Message Service, @wire, and reactive stores. NOT for in-component reactivity.

revenue-lifecycle-management

8
from PranavNagrecha/AwesomeSalesforceSkills

Use this skill when implementing or troubleshooting Salesforce Revenue Lifecycle Management (RLM) — the native Revenue Cloud product covering order-to-cash lifecycle, Dynamic Revenue Orchestrator (DRO) fulfillment plan design, asset amendments, billing schedule creation via Connect API, and invoice management. Triggers on: Dynamic Revenue Orchestrator, RLM order decomposition, DRO fulfillment swimlanes, native Revenue Cloud billing schedule, asset lifecycle management Salesforce. NOT for CPQ quoting or pricing rules (use cpq-* skills), not for the legacy Salesforce Billing managed package with blng__* objects (different product entirely), not for standard Order objects without Revenue Cloud features.

loyalty-management-setup

8
from PranavNagrecha/AwesomeSalesforceSkills

Use this skill when setting up or extending Salesforce Loyalty Management — including program and currency creation, tier group design, qualifying vs. non-qualifying point currency separation, DPE batch job activation, partner loyalty configuration, and member portal setup on Experience Cloud. Triggers on: Loyalty Management setup, loyalty tier setup Salesforce, qualifying points vs redemption points, DPE batch job for loyalty, partner loyalty program Salesforce, loyalty member portal. NOT for Marketing Cloud engagement program design (separate product), not for B2B loyalty via Sales Cloud (standard opportunity, not loyalty program), not for general Experience Cloud site setup (use experience-cloud-setup skill).

scratch-org-management

8
from PranavNagrecha/AwesomeSalesforceSkills

Use this skill when designing, configuring, or troubleshooting scratch orgs: definition file structure, edition selection, allocation limits, Org Shape, CI automation via ScratchOrgInfo, and lifecycle management from the Dev Hub. NOT for SFDX CLI basics (use sf-cli-and-sfdx-essentials), sandbox management, or production org administration.

release-management

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when planning, coordinating, or governing Salesforce releases: version numbering, rollback strategy, release notes, go/no-go criteria, release calendar, and sandbox preview alignment. NOT for deployment mechanics (use devops/post-deployment-validation or devops/change-set-deployment).

pipeline-secrets-management

8
from PranavNagrecha/AwesomeSalesforceSkills

Store and inject Salesforce auth URLs, JWT keys, and API credentials into CI without leaking them. NOT for runtime secrets in Apex.

isv-license-management-and-trialforce

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when an ISV partner is wiring license enforcement, trial provisioning, or feature-flag distribution into a managed package — covers License Management App (LMA) install and registration, Lead/License object lifecycle, Trialforce Management Org (TMO) and Trialforce Source Org (TSO) split, Trialforce templates, SignupRequest API, AppExchange Checkout integration, and Feature Parameters (LmoToSubscriber / SubscriberToLmo) as the cross-org configuration channel. Triggers: 'register package with LMA', 'set up Trialforce', 'add feature parameter to managed package', 'license expired in subscriber org', 'AppExchange Checkout licensing'. NOT for general managed-package version creation, ancestor pinning, or PostInstall handler design (use managed-package-development); NOT for second-generation packaging mechanics (use second-generation-managed-packages); NOT for non-ISV experience-cloud login licensing (use experience-cloud-licensing-model).

api-version-management

8
from PranavNagrecha/AwesomeSalesforceSkills

Use this skill when auditing, upgrading, or standardizing Salesforce API versions across metadata components, sfdx-project.json sourceApiVersion, Apex classes, LWC bundles, Aura bundles, and integration endpoints. Covers version drift detection, retirement risk analysis, and upgrade planning. NOT for REST/SOAP API design patterns (use rest-api-patterns or soap-api-patterns), OAuth configuration (use oauth-flows-and-connected-apps), or Metadata API deployment mechanics (use change-set-deployment or unlocked-package-development).