Beyond basic parent-child, LWC supports compositional patterns for complex UI.
1. Slots for layout.
Parent component defines layout; child fills in. Like CSS Flexbox + named slots.
html <!-- container.html --> <div class="card"> <header><slot name="header"></slot></header> <main><slot></slot></main> <footer><slot name="footer"></slot></footer> </div>
html <!-- usage --> <c-container> <h1 slot="header">Title</h1> <p>Body content</p> <button slot="footer">Action</button> </c-container>
2. Higher-order components (mixins).
Reusable behavior shared across components via JS modules.
`javascript // withLogging.js export const withLogging = (LightningElement) => class extends LightningElement { connectedCallback() { console.log(this.constructor.name + ' mounted'); super.connectedCallback?.(); } };
// usage import { LightningElement } from 'lwc'; import { withLogging } from 'c/withLogging';
export default class MyComponent extends withLogging(LightningElement) { ... } `
3. Dynamic component rendering.
Render different components based on data:
javascript get componentName() { return this.recordType === 'New Business' ? 'c-new-business-view' : 'c-renewal-view'; }
4. Render-prop pattern (functional composition).
Component A provides data; component B (passed in) renders it.
5. Container / Presenter.
Container fetches data; Presenter receives via @api and renders. Stateless presenters easier to test.
6. Event-driven coordination.
Sibling components don't talk directly; coordinate via Lightning Message Service or parent-mediated events.
7. Service layer.
Custom JS modules for shared logic (validation, formatting, computation). Imported by multiple components.
`javascript // utils.js export const formatCurrency = (amount, currency) => { ... };
// component.js import { formatCurrency } from 'c/utils'; `
8. State management.
For complex apps:
- Lightning Message Service for cross-tree state.
- Wire-driven data for reactive updates.
- For Redux-style state: third-party patterns or build your own.
9. Async patterns.
@wirefor reactive.- Imperative
await fetch(...)for one-off. - Loading states / spinners.
- Error states.
10. Progressive enhancement.
- Basic functionality renders fast.
- Advanced features lazy-load.
Architect role: define standards for composition. Without standards, devs invent inconsistent patterns; codebase becomes hard to navigate.
Common pitfalls:
- Inheritance attempted — LWC doesn't support inheritance well; use composition.
- Tightly coupled components — sharing too much state via parent.
- Reinventing the wheel — building components that already exist as standard.
- No state strategy — components fight for ownership of shared state.
