sf-lwc-content: Microcopy and UI Writing for LWC
The words inside a component matter as much as the visual design. Write clear, helpful, human UI text that guides users and reduces confusion.
Core Principles
- Clear over clever — say exactly what happened and what to do next
- Active voice — "Save the record" not "The record will be saved"
- Verb-first buttons — "Create Account" not "Account Creation"
- No jargon — "Something went wrong" not "Null pointer exception in line 42"
- Consistent terminology — pick one word and use it everywhere
Error Messages
Structure: What + Why + What to Do
Every error message answers three questions:
┌─────────────────────────────────────────────┐
│ WHAT happened │ "Record couldn't be saved"
│ WHY it happened │ "Required fields are missing"
│ WHAT TO DO next │ "Fill in Account Name and click Save again"
└─────────────────────────────────────────────┘
Error Templates
| Scenario |
Message |
| Field validation |
{Field Name} is required. Enter a value to continue. |
| Server error |
We couldn't save this record. Check your entries and try again. |
| Permission denied |
You don't have access to {action}. Contact your admin for help. |
| Network error |
We couldn't connect to Salesforce. Check your connection and try again. |
| Not found |
This {record type} was deleted or you don't have access to it. |
| Limit reached |
You've reached the maximum of {limit} {items}. Remove one to add another. |
Error in Code
get userFriendlyError() {
if (!this._error) return '';
if (this._error.body?.message) {
return this._error.body.message;
}
return 'Something went wrong. Try again, or contact your admin if the problem continues.';
}
Anti-Patterns
| Do NOT Say |
Say Instead |
Error: 500 Internal Server Error |
Something went wrong. Try again in a moment. |
FIELD_CUSTOM_VALIDATION_EXCEPTION |
{Validation rule error message text} |
null or blank |
Something unexpected happened. Try again. |
Invalid input |
Enter a valid {field type}. Example: name@company.com |
Empty States
Empty states are opportunities to guide users, not dead ends.
Structure: Explain + Guide + Act
┌─────────────────────────────────────────────┐
│ [Icon or illustration] │
│ │
│ No {items} yet │ ← Explain
│ {Why this is empty or what items are} │ ← Guide
│ [Create {Item}] │ ← Act
└─────────────────────────────────────────────┘
Empty State Templates
| Context |
Title |
Description |
Action |
| First use |
No cases yet |
Cases appear here when customers reach out. |
Create a Case |
| No results |
No matching records |
Try adjusting your filters or search terms. |
Clear Filters |
| Filtered empty |
No {items} match "{query}" |
Check your spelling or try different keywords. |
Clear Search |
| Completed |
All caught up |
You've resolved all open cases. Nice work. |
— |
| Permission |
Nothing to show |
Ask your admin for access to {feature}. |
Request Access |
Button Labels
Rules
- Verb first:
Save Record, Create Contact, Send Email
- Specific over generic:
Save Changes not Submit, Delete Account not OK
- Match the action: the button label should describe what happens when clicked
- Destructive actions: use the verb that matches (
Delete, Remove, Disconnect)
Common Pairs
| Primary |
Secondary |
Context |
Save |
Cancel |
Edit form |
Create {Item} |
Cancel |
New record form |
Delete |
Keep |
Destructive confirmation |
Confirm |
Go Back |
Multi-step process |
Send |
Cancel |
Email/message action |
Apply |
Reset |
Filter/settings |
Anti-Patterns
| Do NOT |
Do Instead |
OK / Yes / No |
Specific: Delete Record / Keep Record |
Submit (generic) |
Save Changes, Create Account, Send Request |
Click Here |
View Details, Download Report |
Process |
Run Report, Calculate Total |
Help Text and Tooltips
When to Use
| Pattern |
Use When |
| Inline help text |
Field needs context every time (format, constraints) |
| Tooltip |
Supplementary info; not needed for task completion |
| Info icon + popover |
Detailed explanation that would clutter inline |
Help Text Templates
| Field Type |
Help Text Pattern |
| Email |
Enter a valid email address. Example: name@company.com |
| Phone |
Include country code for international numbers. Example: +1 (555) 123-4567 |
| Date |
Enter a date in MM/DD/YYYY format. |
| Currency |
Enter the amount without currency symbols. |
| Lookup |
Search by name or record number. |
| Picklist |
Select the option that best describes {context}. |
| Percentage |
Enter a number between 0 and 100. |
Accessibility Note
Tooltips must be keyboard-accessible. Use aria-describedby to link help text to its field:
<lightning-input
label="Annual Revenue"
field-name="AnnualRevenue"
aria-describedby="revenue-help">
</lightning-input>
<div id="revenue-help" class="help-text">
Enter the company's total annual revenue in USD.
</div>
Confirmation Dialogs
Structure: Consequence + Specific Action
┌─────────────────────────────────────────────┐
│ Delete this account? │ ← Question (what will happen)
│ │
│ This will permanently delete "Acme Corp" │ ← Consequence
│ and all related contacts and cases. │
│ This action can't be undone. │
│ │
│ [Cancel] [Delete Account] │ ← Specific labels
└─────────────────────────────────────────────┘
Templates
| Action |
Title |
Body |
Confirm Button |
| Delete record |
Delete this {type}? |
This will permanently delete "{name}" and its related data. This can't be undone. |
Delete {Type} |
| Discard changes |
Discard unsaved changes? |
You have unsaved changes that will be lost. |
Discard Changes |
| Remove from list |
Remove {name}? |
{Name} will be removed from this {list}. You can add them back later. |
Remove |
| Reassign |
Reassign this {type}? |
{Name} will be reassigned from {current} to {new}. |
Reassign |
Toast Messages
Format
{ title: 'Account saved', message: 'Your changes have been saved.', variant: 'success' }
{ title: 'Couldn\'t save record', message: 'Check required fields and try again.', variant: 'error' }
{ title: 'Limited results', message: 'Showing first 200 records. Refine your search.', variant: 'warning' }
{ title: 'Record updated', message: 'Changes made by another user have been loaded.', variant: 'info' }
Rules
- Title: 2-4 words, sentence case
- Message: 1 sentence, actionable for errors
- Success toasts: optional message (title alone is often sufficient)
- Error toasts: always include a message with guidance
Placeholder Text
Rules
- Placeholders are examples, not labels — never replace a label with a placeholder
- Use realistic examples:
Search accounts... not Type here
- Keep short: max 30-40 characters
Templates
| Field |
Placeholder |
| Search |
Search {items}... |
| Name |
Enter full name |
| Email |
name@company.com |
| Description |
Describe the issue... |
| URL |
https://example.com |
Internationalization Readiness
String Patterns
- Never concatenate translated strings — word order varies by language
- Use Custom Labels for all user-facing text
- Allow 40% expansion for translated text (German/French are longer than English)
- Avoid text in images — it can't be translated
import SAVE_LABEL from '@salesforce/label/c.Save_Changes';
import ERROR_TITLE from '@salesforce/label/c.Error_Title';
export default class MyComponent extends LightningElement {
labels = { SAVE_LABEL, ERROR_TITLE };
}
<lightning-button label={labels.SAVE_LABEL}></lightning-button>
Scoring Rubric (100 Points)
| Category |
Points |
Pass Criteria |
| Error Messages |
25 |
All errors follow what/why/do structure; no raw exceptions shown |
| Empty States |
20 |
Every list/table has an empty state with guidance and action |
| Button Labels |
15 |
Verb-first, specific, destructive actions clearly labeled |
| Help Text |
15 |
Fields that need context have help text; accessible linking |
| Confirmation Dialogs |
15 |
Destructive actions confirmed; specific labels on buttons |
| i18n Ready |
10 |
Custom Labels used; no string concatenation; expansion room |
Cross-Skill Integration
| Skill |
Relationship |
| sf-lwc-ux |
Empty/error/loading states need well-written content |
| sf-lwc-review |
Audit includes content quality checks |
| sf-lwc-page-composition |
App Builder property labels and descriptions need good copy |
| sf-lwc-mobile |
Mobile copy must be even more concise |