Agent skill
sf-lwc
Scaffold Lightning Web Components with HTML templates, JS controllers, CSS with SLDS compliance, js-meta.xml config, and Jest tests. Use when asked about Lightning Web Components, LWC, component scaffolding, or Jest tests for LWC. Activate on .js-meta.xml files, mentions of "LWC", "Lightning Web Component", "wire adapter", "lightning component", or "@api/@wire/@track decorators".
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/sf-lwc
Metadata
Additional technical details for this skill
- tags
- salesforce, lwc, lightning-web-components, jest, frontend
- author
- clientell
- version
- 1.0.0
SKILL.md
LWC Scaffolder
You are a Salesforce Lightning Web Component specialist. Generate complete, production-ready LWC bundles.
LWC Bundle Structure
Every LWC consists of these files in force-app/main/default/lwc/componentName/:
myComponent/
├── myComponent.html # Template
├── myComponent.js # Controller
├── myComponent.css # Styles (SLDS-compliant)
├── myComponent.js-meta.xml # Configuration
└── __tests__/
└── myComponent.test.js # Jest tests
Naming Conventions
- Bundle folder:
camelCase(e.g.,accountList) - HTML markup:
kebab-casewithc-namespace (e.g.,<c-account-list>) - JS class:
PascalCase(e.g.,AccountList) - CSS: follows component name
JavaScript Controller Pattern
import { LightningElement, api, wire, track } from 'lwc';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { NavigationMixin } from 'lightning/navigation';
import getRecords from '@salesforce/apex/MyController.getRecords';
import ACCOUNT_NAME from '@salesforce/schema/Account.Name';
export default class MyComponent extends NavigationMixin(LightningElement) {
@api recordId;
@track records = [];
error;
isLoading = false;
@wire(getRecords, { recordId: '$recordId' })
wiredRecords({ error, data }) {
if (data) {
this.records = data;
this.error = undefined;
} else if (error) {
this.error = error;
this.records = [];
}
}
handleAction() {
this.isLoading = true;
imperativeMethod({ param: this.recordId })
.then(result => {
this.dispatchEvent(new ShowToastEvent({
title: 'Success',
message: 'Operation completed',
variant: 'success'
}));
})
.catch(error => {
this.dispatchEvent(new ShowToastEvent({
title: 'Error',
message: error.body?.message || 'An error occurred',
variant: 'error'
}));
})
.finally(() => {
this.isLoading = false;
});
}
}
Meta XML Configuration
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>62.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__RecordPage</target>
<target>lightning__AppPage</target>
<target>lightning__HomePage</target>
</targets>
<targetConfigs>
<targetConfig targets="lightning__RecordPage">
<objects>
<object>Account</object>
</objects>
<property name="title" type="String" default="My Component"/>
</targetConfig>
</targetConfigs>
</LightningComponentBundle>
Jest Test Pattern
import { createElement } from 'lwc';
import MyComponent from 'c/myComponent';
import getRecords from '@salesforce/apex/MyController.getRecords';
// Mock Apex method
jest.mock('@salesforce/apex/MyController.getRecords', () => ({
default: jest.fn()
}), { virtual: true });
const MOCK_DATA = [
{ Id: '001xx000003ABCDEF', Name: 'Test Account' }
];
describe('c-my-component', () => {
afterEach(() => {
while (document.body.firstChild) {
document.body.removeChild(document.body.firstChild);
}
jest.clearAllMocks();
});
it('renders records when data is returned', async () => {
getRecords.mockResolvedValue(MOCK_DATA);
const element = createElement('c-my-component', { is: MyComponent });
element.recordId = '001xx000003ABCDEF';
document.body.appendChild(element);
await Promise.resolve();
const items = element.shadowRoot.querySelectorAll('.record-item');
expect(items.length).toBe(1);
});
it('shows error when apex call fails', async () => {
getRecords.mockRejectedValue(new Error('Test error'));
const element = createElement('c-my-component', { is: MyComponent });
document.body.appendChild(element);
await Promise.resolve();
const errorEl = element.shadowRoot.querySelector('.error-message');
expect(errorEl).toBeTruthy();
});
});
Lightning Data Service (LDS)
Use lightning/uiRecordApi for CRUD without Apex:
getRecordwire adapter — read records with field-level securitycreateRecord,updateRecord,deleteRecord— imperative CRUDgetObjectInfo,getPicklistValues— metadata accessrefreshApex()— invalidate wire cache after mutations- When to use: Simple CRUD. Use Apex wire for complex queries or business logic.
Lifecycle Hooks
| Hook | When | Common Use |
|---|---|---|
constructor() |
Component created | Initialize state |
connectedCallback() |
Inserted into DOM | Fetch data, add listeners |
renderedCallback() |
After each render | DOM manipulation (guard with flag!) |
disconnectedCallback() |
Removed from DOM | Cleanup listeners, unsubscribe LMS |
errorCallback(error, stack) |
Child error | Error boundary, logging |
Navigation
Use NavigationMixin with page reference types:
standard__recordPage— view/edit/clone records (requiresrecordId,actionName)standard__objectPage— object home/list/new (requiresobjectApiName,actionName)standard__namedPage— standard pages (home, chatter, filePreview)standard__webPage— external URLs (requiresurl)
Lightning Message Service (LMS)
Cross-DOM communication between LWC, Aura, and Visualforce:
- Define message channel in
.messageChannel-meta.xml publish(messageContext, channel, payload)to sendsubscribe(messageContext, channel, handler, {scope: APPLICATION_SCOPE})to receive- Always
unsubscribe()indisconnectedCallback()to prevent memory leaks
Shadow DOM vs Light DOM
- Shadow DOM (default): CSS isolation, encapsulated DOM — use for most components
- Light DOM (
lwc:dom="light"): No encapsulation — use when you need cross-component ARIA references, global CSS, or third-party library DOM access - Shadow DOM blocks
document.querySelector()from outside — usethis.template.querySelector()inside
Rules
- Always use SLDS classes for styling — avoid custom CSS when SLDS has a utility
- Use
@apifor public properties, reactive by default - Use
@wirefor declarative data fetching - Use imperative Apex calls for user-initiated actions
- Handle loading states and errors in every component
- Use
lightning-record-form/lightning-record-edit-formfor simple CRUD - Dispatch custom events for child-to-parent communication
- Use
MessageChannelfor cross-DOM communication
Gotchas
@trackis deprecated — all properties are reactive by default since API v40+renderedCallback()fires after EVERY render — always guard with a boolean flag to prevent infinite loops- LDS cache is NOT automatically refreshed — call
refreshApex(wiredProperty)after imperative mutations - LMS subscriptions MUST unsubscribe in
disconnectedCallback()to prevent memory leaks - Shadow DOM blocks ID-based ARIA references (
aria-labelledby) across components — use Light DOM for accessibility - CSP blocks
eval(),new Function(), and inline<script>— load third-party libraries vialoadScript()from Static Resources @apiproperties are read-only in the component — parent sets them, child cannot mutate- Wire adapters re-fire when reactive parameters change — avoid unnecessary parameter changes
Workflow
- Understand the component requirements
- Check for existing components that can be extended
- Generate all bundle files (HTML, JS, CSS, meta.xml)
- Generate Jest test file with mock data
- Deploy:
sf project deploy start -d force-app/main/default/lwc/componentName/
References
- LWC Patterns — LDS, navigation, LMS, datatable, custom events, slots, accessibility, SLDS, third-party libs, dynamic components, Experience Cloud
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?