13.2 UI Security, Performance & Accessibility Patterns
Key Takeaways
- Treat client UI as untrusted for security: enforce CRUD/FLS/sharing in Apex; mitigate XSS by avoiding raw HTML injection and respecting Lightning CSP constraints
- Locker Service and Lightning Web Security isolate components so one namespace cannot freely access another’s DOM, data, or privileged APIs
- Prefer base Lightning components, LDS/@wire caching, lazy rendering, and fewer Apex round trips over chatty imperative calls and large eager payloads
- Accessibility for certification awareness means semantic structure, keyboard use, labels, and ARIA only when needed—base components already encode many SLDS a11y patterns
- Static resources are cacheable org assets for CSS/JS/images; version and reference them properly rather than inlining huge scripts on every render
13.2 UI Security, Performance & Accessibility Patterns
Quick Answer: Secure Lightning UI by never trusting the browser as a security boundary, blocking XSS (no careless DOM/HTML injection), and relying on CSP, Locker Service / Lightning Web Security, and server-side CRUD/FLS/sharing. Speed UIs with @wire/LDS caching, lazy loading, and fewer Apex round trips. Prefer base Lightning components for accessibility and use static resources for cacheable assets.
Section 13.1 covered where UI lives. This section covers how custom UI stays safe, fast, and usable—themes that appear in User Interface and cross-cut Security/Testing mindsets on Platform Developer I.
Security Mindset for Lightning UI
The browser is not your enforcement layer
Anything in LWC/Aura/Visualforce JavaScript can be inspected or manipulated by a determined user. Therefore:
- Authorization decisions belong in Apex (
with sharing, explicit CRUD/FLS checks orSecurity.stripInaccessible, carefulwithout sharingonly when justified) - UI hiding (CSS,
lwc:if, disabled buttons) is UX, not security - Never ship secrets (passwords, long-lived tokens, other users’ private data) to the client “because the component is hidden”
Exam scenarios that show a component filtering records only in JavaScript while Apex returns all rows are wrong—fix on the server.
Cross-site scripting (XSS)
XSS occurs when untrusted strings are interpreted as HTML/JS in the browser—for example, a Contact title of <script>…</script> or an image tag with an onerror handler if rendered unsafely.
High-risk patterns to avoid or tightly control:
| Pattern | Risk |
|---|---|
Setting innerHTML from user/record data | Direct HTML injection |
lwc:dom="manual" + unchecked HTML writes | Bypasses normal template escaping discipline |
Visualforce escape="false" on untrusted data | Classic VF XSS vector |
| Building HTML strings in JS and injecting into the DOM | Easy to get wrong |
eval, Function constructor, or injecting third-party scripts freely | Code injection / CSP conflicts |
Safer defaults:
- Render text through normal LWC template bindings (
{name}) so content is treated as text - Use base components (
lightning-formatted-rich-textand related controls only with trusted or properly sanitized sources—and know rich text is a deliberate exception that must be handled carefully) - Prefer structured UI (properties, slots, child components) over string-built HTML
- Validate and encode on the server when accepting HTML-ish input
Exam language: If a stem asks how to display untrusted user input safely, choose escaped text binding / avoid DOM injection, not “turn off Locker” or “use innerHTML for speed.”
Content Security Policy (CSP) in Lightning
Lightning Experience applies a Content Security Policy that restricts:
- Inline scripts (in many contexts)
- Loading JavaScript from arbitrary external origins
- Some dynamic code execution patterns
Implications for developers:
- Host libraries as static resources (or approved platform mechanisms) rather than hot-linking random CDNs when policy blocks them
- Prefer platform modules and LWC imports over injecting
<script src="https://…">tags - CSP errors in the browser console often mean “this script/style source is not allowed,” not “Apex failed”
You do not need to memorize every CSP header directive for PDI, but you must associate Lightning + CSP with limits on inline/third-party script and the need for compliant asset loading.
Locker Service and Lightning Web Security (Conceptual)
Salesforce isolates components so that one component cannot casually reach into another’s private DOM or JavaScript context. Two related names appear in materials:
| Concept | How to think about it on the exam |
|---|---|
| Lightning Locker (Locker Service) | Legacy / long-taught isolation model for Lightning components—DOM access restricted, secure wrappers, namespace isolation |
| Lightning Web Security (LWS) | Newer security architecture evolving isolation for LWC with modern browser capabilities |
What you must retain conceptually (not engine internals):
- Components are sandboxed relative to each other
- You communicate via public properties, events, LMS, not by scraping another component’s internal nodes
- Global browser APIs may be restricted or wrapped
- Isolation supports multi-vendor / multi-team pages on one flexipage (AppExchange + custom + standard)
Do not answer exam questions with “use document.querySelector on the whole page to read another team’s component state.” That fights Locker/LWS design.
Avoid DOM injection and fragile DOM coupling
Beyond XSS, heavy manual DOM work is brittle under Locker/LWS and Shadow DOM:
- Use
this.template.querySelectoronly inside your LWC for your own template elements - Do not rely on global IDs from unrelated components
- Prefer declarative rendering (
lwc:if, lists, base components) over imperative DOM construction - When third-party libraries need a root node, isolate them carefully and understand security/CSP trade-offs
Performance Patterns
Lightning performance problems usually come from too much work on load and too many server round trips, not from “JavaScript is slow” in the abstract.
Prefer efficient data access
| Pattern | Why it helps |
|---|---|
Lightning Data Service / ui*Api wires | Platform-managed record cache; avoids custom Apex for simple CRUD/read |
@wire with reactive params | Declarative loading; framework can reuse/cache adapter results |
Cacheable Apex (@AuraEnabled(cacheable=true)) | Enables wire; results cacheable for reads—no DML in cacheable methods |
| Imperative Apex only when needed | User-driven actions, DML, or non-wire scenarios |
| Refresh only what changed | refreshApex / LDS notify patterns instead of reloading everything blindly |
Anti-pattern: connectedCallback fires three imperative Apex methods that each re-query the same accounts on every component instance on the page.
Minimize Apex round trips
Bundle server work:
- One Apex method returning a DTO with all data the view needs beats five chatty methods
- Do not call Apex inside loops on the client for each row
- Push filtering/sorting to SOQL when it reduces payload and enforces security
- Debounce user input (typeahead) so you do not hit the server per keystroke without limit
Remember governors still apply on the server; chatty UI multiplies limit risk under concurrent use.
Lazy loading and progressive UI
- Do not load every related list, chart, and heavy datatable on first paint if the user may never open that tab
- Render expensive child components when a tab becomes active or a section expands
- Use spinners and partial UI so first interaction is fast
- Keep component trees shallow when possible; large nested trees increase render cost
Payload and render hygiene
- Query only needed fields
- Paginate large tables (
lightning-datatablewith server paging patterns) - Avoid huge client-side arrays of entire sObjects for trivial displays
- Prefer SLDS/base components over giant custom CSS frameworks downloaded per page
Accessibility (Certification-Relevant Awareness)
Platform Developer I will not make you a full WCAG auditor, but you should know accessible UI is part of Lightning design and base components help.
Practical a11y checklist for custom UI
| Concern | Practice |
|---|---|
| Semantics | Use headings, lists, and correct control types—not clickable <div>s for buttons |
| Labels | Every input needs a visible label or accessible name (lightning-input label attribute) |
| Keyboard | Users must operate controls without a mouse; do not trap focus carelessly |
| Focus | Manage focus when opening/closing modals (base lightning-modal patterns help) |
| Color | Do not communicate state by color alone |
| ARIA | Use ARIA attributes when native semantics are insufficient—not as a substitute for correct elements |
| SLDS / base components | Prefer them; they encode many keyboard and ARIA behaviors |
Exam heuristic: “Build an accessible form in Lightning” → base Lightning input components + labels, not raw unlabeled HTML inputs with click-only handlers.
ARIA roles such as aria-live, aria-label, and role="dialog" appear when custom non-base widgets are unavoidable. Misused ARIA is worse than none—prefer native elements first.
Static Resources and Caching
Static resources store CSS, JavaScript libraries, fonts, and images in the org:
- Referenced from LWC via
@salesforce/resourceUrl/ResourceName(and VF via$Resource) - Served with caching headers so browsers reuse assets across pages
- Versioned with the org upload; zip resources allow folder paths
Why exams mention them for performance:
- Cached assets reduce repeat download cost versus inlining large scripts in every component render
- Shared libraries load once and serve many components
- Combined with CSP-friendly hosting, static resources are the standard place for approved client libraries
Caveats:
- Large unoptimized libraries still hurt first load—prefer platform modules when available
- Cache behavior means users may keep an old file until resource updates and references refresh—plan cache-busting via updated static resource versions when releasing breaking JS changes
- Static resources are not a substitute for Apex security or secret storage
Putting Security, Performance, and A11y Together
A well-designed LWC record widget typically:
- Uses
@wire(getRecord)or cacheable Apex for reads (performance + platform cache) - Performs DML in non-cacheable Apex with sharing and FLS enforced (security)
- Renders with
lightning-record-view-form/ inputs / datatable (a11y + less custom HTML) - Avoids
innerHTMLfor user fields (XSS) - Lazy-loads secondary panels (performance)
- Loads optional charting CSS/JS from a static resource if not available as platform modules (CSP + caching)
Anti-pattern summary the exam wants you to reject
| Anti-pattern | Prefer |
|---|---|
| Apex returns all fields/rows; JS hides restricted ones | Server-side security |
innerHTML = record.Name | Text binding / safe formatting |
| Five imperative Apex calls on every keystroke | Debounce + fewer cacheable wires |
| Custom div-buttons with no labels | lightning-button / proper labels |
| Script tags to random CDNs blocked by CSP | Static resources / platform imports |
document.querySelector into another component | Events / @api / LMS |
Bottom line: For Platform Developer I, UI quality means secure by server enforcement and no XSS/DOM injection, isolated by Locker/LWS, fast via wire/LDS, lazy load, and fewer round trips, accessible via base components and basic ARIA/label discipline, and efficient assets via static resource caching—all while composing on the Lightning pages you designed in 13.1.
A developer wants to show a custom text field that may contain characters like < and > entered by users. Which approach best reduces XSS risk in LWC?
Which strategy best improves Lightning component performance when displaying a read-only record summary?
Why do Platform Developer I materials emphasize base Lightning components for accessibility?