Skip to main content

Best practices

Naming convention

// Use kebab-case with meaningful prefixes
customElements.define('my-company-button', MyButton);
customElements.define('ui-modal-dialog', ModalDialog);

Property compared to attribute design

class MyComponent extends LitElement {
// Simple types as attributes
@property() title: string = '';

// Complex types as properties only
@property({ attribute: false })
complexData: { items: any[] } = { items: [] };

// Boolean attributes
@property({ type: Boolean })
disabled: boolean = false;
}

Event design

// Create descriptive, bubbling events
private _handleSubmit() {
this.dispatchEvent(new CustomEvent('form-submit', {
detail: { formData: this.getFormData() },
bubbles: true,
composed: true // Cross shadow DOM boundary
}));
}

Accessibility

render() {
return html`
<button
?disabled=${this.disabled}
aria-label=${this.ariaLabel || 'Submit form'}
@click=${this._handleClick}
>
<slot></slot>
</button>
`;
}

Performance optimisation

class OptimizedComponent extends LitElement {
// Prevent unnecessary re-renders
shouldUpdate(changedProperties: Map<string, any>): boolean {
return changedProperties.has('criticalProp');
}

// Use willUpdate for derived data
willUpdate(changedProperties: Map<string, any>) {
if (changedProperties.has('data')) {
this.processedData = this.processData(this.data);
}
}
}