---
name: LWC Enterprise Patterns
description: This skill should be used when the user asks to "create lwc component", "lightning web component", "component architecture", "lwc state management", "lwc testing", "jest test", or mentions container/presentational patterns, pub-sub, or LWC best practices.
version: 0.1.0
---
# LWC Enterprise Patterns
## Overview
Lightning Web Components (LWC) enterprise patterns provide architectural guidance for building scalable, maintainable component libraries for Salesforce managed packages. This skill covers proven patterns for component architecture, state management, event communication, and testing strategies that enable teams to deliver high-quality, reusable components.
Apply these patterns when building component libraries that require consistency, testability, and long-term maintainability across large development teams.
## Component Architecture Patterns
### Container/Presentational Pattern
Separate business logic from presentation by using container components to manage state and data operations while presentational components focus solely on rendering UI.
**Container Components:**
- Fetch data from Salesforce (wire adapters, imperative Apex)
- Manage component state
- Handle business logic and transformations
- Coordinate child component interactions
- Pass data and callbacks to presentational components
**Presentational Components:**
- Receive data via `@api` properties
- Emit events for user interactions
- No direct Salesforce data access
- Stateless where possible
- Highly reusable across contexts
**When to Use:**
- Complex components with significant business logic
- Components requiring data from multiple sources
- Reusable UI elements used across different contexts
- Components requiring comprehensive testing
**Benefits:**
- Clear separation of concerns
- Easier unit testing (presentational components mock-free)
- Reusability of presentational components
- Simplified maintenance
**Example Structure:**
```
accountDashboard/ // Container
accountDashboard.js // Handles @wire getAccount, state
accountDashboard.html // Minimal template
accountDashboard.css
__tests__/
accountCard/ // Presentational
accountCard.js // @api account, dispatches events
accountCard.html // Rich UI template
accountCard.css
__tests__/
```
See `examples/containerComponent/` and `examples/presentationalComponent/` for complete implementations.
### Compound Components
Build components that work together as a coordinated system while maintaining flexibility and composability.
**Pattern:**
- Parent component provides context via properties
- Child components share implicit communication via parent
- Children can be used independently or within parent
- Flexible composition for different use cases
**Implementation Approaches:**
**1. Property Pass-Through:**
Parent component receives configuration and passes it to children.
**2. Event Coordination:**
Parent listens to child events and coordinates responses across siblings.
**3. Context Sharing:**
Use CSS custom properties or data attributes for shared styling context.
**When to Use:**
- Related components that work better together
- Configurable component groups
- Components requiring coordinated state changes
- Building design system primitives
**Example Use Case:**
```
// Compound components for a filterable list
```
### Base Components
Create abstract base components that encapsulate common functionality and extend them for specific use cases.
**Pattern:**
- Create a base component with shared logic
- Extend using composition (slots) not inheritance
- Use mixins for cross-cutting concerns
- Implement consistent interfaces via `@api` properties
**Common Base Components:**
- Data table bases with sorting, filtering
- Form field bases with validation
- Modal/dialog bases with accessibility
- Card layout bases with standardized structure
**Best Practices:**
- Keep base components focused on single responsibility
- Document extension points clearly
- Provide default implementations that can be overridden
- Use slots for flexible content injection
## State Management Patterns
### Local State (Component State)
Use component properties decorated with `@track` for local, encapsulated state.
**When to Use:**
- State only relevant to single component
- Temporary UI state (expanded/collapsed, selected tab)
- Form input values before submission
**Best Practices:**
- Minimize tracked properties for performance
- Use primitive types when possible
- Avoid deep object tracking
- Initialize state in constructor or property declaration
### Shared State (Parent-Child)
Pass state down through properties and emit events upward for state changes.
**Pattern:**
- Parent owns state
- Children receive state via `@api` properties
- Children dispatch CustomEvents for changes
- Parent updates state and re-renders children
**When to Use:**
- Related components in parent-child hierarchy
- State needs to be synchronized across siblings
- Parent orchestrates child interactions
**Best Practices:**
- Use immutable update patterns
- Keep event payloads simple
- Name events consistently (e.g., `itemselected`, `filterchanged`)
- Document event contracts clearly
### Pub-Sub Pattern
Implement publish-subscribe for communication across unrelated components using Lightning Message Service or custom pub-sub.
**Lightning Message Service (LMS):**
- Platform-native pub-sub mechanism
- Works across LWC, Aura, Visualforce
- Scoped to page or application
- Requires message channel definition
**When to Use:**
- Cross-component communication without direct relationship
- Broadcasting changes to multiple subscribers
- Decoupled architecture requirements
- Communication across different page regions
**Custom Pub-Sub Implementation:**
- Use for simple, non-critical scenarios
- Implement using JavaScript module
- Manage subscriptions and cleanup
- Consider memory leak prevention
**Best Practices:**
- Unsubscribe in `disconnectedCallback()`
- Use specific message channels for different concerns
- Keep message payloads minimal
- Document message contracts
See `references/state-management.md` for implementation examples.
### Service Components
Create JavaScript modules that act as shared services for data access, caching, and business logic.
**Pattern:**
- Export singleton service module
- Encapsulate Apex calls and caching
- Provide consistent API for data operations
- Manage in-flight request deduplication
**When to Use:**
- Shared data access across components
- Implementing client-side caching
- Centralizing business logic
- Managing complex asynchronous workflows
**Implementation:**
```javascript
// dataService.js
import getRecords from '@salesforce/apex/Controller.getRecords';
const cache = new Map();
let inFlightRequests = new Map();
export async function fetchRecords(params) {
const cacheKey = JSON.stringify(params);
if (cache.has(cacheKey)) {
return cache.get(cacheKey);
}
if (inFlightRequests.has(cacheKey)) {
return inFlightRequests.get(cacheKey);
}
const promise = getRecords(params);
inFlightRequests.set(cacheKey, promise);
try {
const result = await promise;
cache.set(cacheKey, result);
return result;
} finally {
inFlightRequests.delete(cacheKey);
}
}
```
## Event Communication Patterns
### Custom Events
Dispatch CustomEvents for component-to-component communication with proper bubbling and composition.
**Event Design Principles:**
- Use lowercase, hyphenated event names
- Include relevant data in `detail` object
- Set `bubbles: true` for events crossing shadow boundaries
- Set `composed: true` for events crossing component boundaries
**Implementation:**
```javascript
// Dispatching
this.dispatchEvent(new CustomEvent('itemselected', {
detail: { itemId: this.selectedId },
bubbles: true,
composed: true
}));
// Handling in parent
```
**Best Practices:**
- Keep event names semantic and descriptive
- Document event contracts in component JSDoc
- Include only necessary data in `detail`
- Use consistent event naming conventions across library
### Event Delegation
Handle events at parent level for performance when dealing with many child elements.
**Pattern:**
- Attach event listener to parent container
- Use `event.target` to identify specific child
- Reduce number of event listeners
- Improve performance with large lists
**When to Use:**
- Rendering lists with many interactive items
- Dynamic content with unknown number of children
- Performance-critical scenarios
### Message Service Integration
Integrate Lightning Message Service for cross-namespace and cross-framework communication.
**Setup:**
1. Create message channel in metadata
2. Import message channel in component
3. Subscribe/publish messages
4. Clean up subscription
**Implementation:**
```javascript
import { LightningElement, wire } from 'lwc';
import { publish, subscribe, MessageContext } from 'lightning/messageService';
import RECORD_SELECTED from '@salesforce/messageChannel/RecordSelected__c';
export default class Publisher extends LightningElement {
@wire(MessageContext)
messageContext;
handleSelect(event) {
const message = { recordId: event.detail.id };
publish(this.messageContext, RECORD_SELECTED, message);
}
}
```
## Testing Patterns
### Unit Testing with Jest
Write comprehensive Jest tests for LWC components following enterprise testing patterns.
**Test Structure:**
```javascript
import { createElement } from 'lwc';
import ComponentName from 'c/componentName';
describe('c-component-name', () => {
afterEach(() => {
while (document.body.firstChild) {
document.body.removeChild(document.body.firstChild);
}
});
it('should render correctly with valid data', () => {
// Arrange
const element = createElement('c-component-name', {
is: ComponentName
});
// Act
document.body.appendChild(element);
// Assert
expect(element.shadowRoot.querySelector('.className')).not.toBeNull();
});
});
```
### Testing Patterns by Component Type
**Container Components:**
- Mock Apex calls using `@salesforce/apex` mocks
- Test data transformation logic
- Verify correct data passed to children
- Test error handling scenarios
- Verify loading states
**Presentational Components:**
- Test rendering with various prop combinations
- Verify event dispatching with correct payloads
- Test conditional rendering
- Validate accessibility attributes
- Test user interactions
**Example - Testing Events:**
```javascript
it('should dispatch event when button clicked', () => {
const element = createElement('c-component', { is: Component });
const handler = jest.fn();
element.addEventListener('itemselected', handler);
document.body.appendChild(element);
const button = element.shadowRoot.querySelector('button');
button.click();
expect(handler).toHaveBeenCalledTimes(1);
expect(handler.mock.calls[0][0].detail).toEqual({ itemId: '123' });
});
```
### Mocking Strategies
**Apex Methods:**
```javascript
import getAccounts from '@salesforce/apex/AccountController.getAccounts';
jest.mock(
'@salesforce/apex/AccountController.getAccounts',
() => ({ default: jest.fn() }),
{ virtual: true }
);
// In test
getAccounts.mockResolvedValue([{ Id: '001', Name: 'Test' }]);
```
**Wire Adapters:**
```javascript
import { getRecord } from 'lightning/uiRecordApi';
jest.mock('lightning/uiRecordApi', () => ({
getRecord: jest.fn()
}), { virtual: true });
// In test
import { emit } from '@salesforce/sfdx-lwc-jest';
emit('getRecord', { data: mockRecord });
```
**User Permissions:**
```javascript
import hasPermission from '@salesforce/userPermission/CustomPermission';
jest.mock('@salesforce/userPermission/CustomPermission', () => ({
default: true
}), { virtual: true });
```
See `references/testing-patterns.md` for comprehensive testing examples.
## Accessibility Best Practices
### ARIA and Semantic HTML
Use semantic HTML elements and ARIA attributes for screen reader support.
**Key Practices:**
- Use `