Build Lightning Web Components for external-facing Experience Cloud sites. Different design rules apply compared to internal Lightning pages — public audiences, branding requirements, SEO, and guest user security.
Core Principles
1Brand-first, not SLDS-first — external sites use customer branding, not Salesforce blue
2Guest-safe — every component must handle unauthenticated users gracefully
3Performance — external sites face real-world network conditions
4SEO-aware — content must be crawlable and metadata-rich
5Responsive — external users are on any device, not just desktop
Experience Cloud vs Internal Lightning
| Aspect | Internal Lightning | Experience Cloud |
| Audience | Employees | Customers, partners, public |
| Branding | Salesforce/org theme | Custom brand colors, fonts, logos |
| Authentication | Always logged in | Guest users, self-registration |
| CSS scope | Shadow DOM only | Shadow DOM + global theme CSS |
| Navigation | Lightning tabs/app | Community navigation, URL routing |
| Performance | Corporate network | Public internet, mobile, slow |
| SEO | Not applicable | Critical for public sites |
Theme Customization
Experience Cloud sites use a separate theme system. Components should consume theme tokens, not hardcode brand colors.
Theme Token Consumption
.hero-banner {
background-color: var(--dxp-g-root, var(--slds-g-color-surface-1, #ffffff));
color: var(--dxp-g-root-contrast, var(--slds-g-color-on-surface-1, #181818));
}
.brand-accent {
color: var(--dxp-s-brand-1, var(--slds-g-color-accent-1, #0176d3));
}
.brand-button {
background: var(--dxp-s-brand-1, var(--slds-g-color-accent-1, #0176d3));
color: var(--dxp-s-brand-1-contrast, var(--slds-g-color-on-accent-1, #ffffff));
border-radius: var(--dxp-s-button-radius,
var(--slds-g-radius-border-2, 0.25rem));
}
.nav-link {
color: var(--dxp-s-link-text-color, var(--slds-g-color-accent-1, #0176d3));
}
.nav-link: hover {
color: var(--dxp-s-link-text-color-hover, var(--slds-g-color-accent-2, #014486));
}
DXP Token Categories
| Prefix | Category | Examples |
--dxp-g- | Global | root, root-contrast, root-inverse |
--dxp-s-brand- | Brand colors | brand-1, brand-1-contrast, brand-2 |
--dxp-s-link- | Links | link-text-color, link-text-color-hover |
--dxp-s-button- | Buttons | button-radius, button-color |
--dxp-s-text- | Typography | text-heading-large, text-body |
Fallback Chain
Always fall back from DXP tokens to SLDS hooks to literal values:
color: var(--dxp-s-brand-1, var(--slds-g-color-accent-1, #0176d3));
This ensures the component works in Experience Cloud (DXP tokens), internal Lightning (SLDS hooks), and degraded environments (literal fallback).
Guest User Design
Authentication-Aware Components
import { LightningElement, wire } from class="code-string">'lwc';
import isGuest from class="code-string">'@salesforce/user/isGuest';
import Id from class="code-string">'@salesforce/user/Id';
export default class MyComponent extends LightningElement {
get isAuthenticated() {
return !isGuest;
}
get userId() {
return Id;
}
}
<class="code-tag">template>
class="code-comment"><!-- Authenticated: full experience -->
<class="code-tag">template if:true={isAuthenticated}>
<class="code-tag">c-full-dashboard></class="code-tag">c-full-dashboard>
</class="code-tag">template>
class="code-comment"><!-- Guest: limited experience with CTA to log in -->
<class="code-tag">template if:false={isAuthenticated}>
<class="code-tag">div class="guest-cta">
<class="code-tag">h2 class="guest-cta__title">Sign in to view your dashboard</class="code-tag">h2>
<class="code-tag">p class="guest-cta__description">
Access your account details, open cases, and recent activity.
</class="code-tag">p>
<class="code-tag">lightning-button label="Sign In" variant="brand" onclick={handleLogin}>
</class="code-tag">lightning-button>
</class="code-tag">div>
</class="code-tag">template>
</class="code-tag">template>
Guest User Security Checklist
- Never expose record IDs, org IDs, or internal URLs to guests
- Never query data without
WITH SECURITY_ENFORCED or FLS checks
- Use
@AuraEnabled(cacheable=true) for guest-visible Apex methods
- Validate all input from guest users (treat as untrusted)
- Never expose admin email addresses or internal team names
Navigation Patterns
import { NavigationMixin } from class="code-string">'lightning/navigation';
export default class MyComponent extends NavigationMixin(LightningElement) {
navigateToPage(pageName) {
this[NavigationMixin.Navigate]({
type: class="code-string">'comm__namedPage',
attributes: { name: pageName }
});
}
navigateToRecord(recordId) {
this[NavigationMixin.Navigate]({
type: class="code-string">'standard__recordPage',
attributes: {
recordId: recordId,
actionName: class="code-string">'view'
}
});
}
navigateToExternalUrl(url) {
this[NavigationMixin.Navigate]({
type: class="code-string">'standard__webPage',
attributes: { url }
});
}
}
Breadcrumb Pattern for Sites
<class="code-tag">template>
<class="code-tag">nav aria-label="Breadcrumb">
<class="code-tag">ol class="breadcrumb">
<class="code-tag">template for:each={breadcrumbs} for:item="crumb">
<class="code-tag">li key={crumb.id} class="breadcrumb__item">
<class="code-tag">a if:false={crumb.isCurrent}
href={crumb.url}
onclick={handleNavigate}
data-page={crumb.page}>
{crumb.label}
</class="code-tag">a>
<class="code-tag">span if:true={crumb.isCurrent} aria-current="page">
{crumb.label}
</class="code-tag">span>
</class="code-tag">li>
</class="code-tag">template>
</class="code-tag">ol>
</class="code-tag">nav>
</class="code-tag">template>
Experience Builder Configuration
meta.xml for Experience Cloud
<?xml version="1.0" encoding="UTF-8"?>
<class="code-tag">LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<class="code-tag">apiVersion>62.0</class="code-tag">apiVersion>
<class="code-tag">isExposed>true</class="code-tag">isExposed>
<class="code-tag">masterLabel>Customer Knowledge Base</class="code-tag">masterLabel>
<class="code-tag">description>Searchable knowledge articles for site visitors.</class="code-tag">description>
<class="code-tag">targets>
<class="code-tag">target>lightningCommunity__Page</class="code-tag">target>
<class="code-tag">target>lightningCommunity__Default</class="code-tag">target>
</class="code-tag">targets>
<class="code-tag">targetConfigs>
<class="code-tag">targetConfig targets="lightningCommunity__Default">
<class="code-tag">property name="heading" type="String" label="Section Heading"
default="Knowledge Base" />
<class="code-tag">property name="maxArticles" type="Integer" label="Articles to Show"
default="10" min="3" max="50" />
<class="code-tag">property name="showSearch" type="Boolean" label="Show Search Bar"
default="true" />
</class="code-tag">targetConfig>
</class="code-tag">targetConfigs>
</class="code-tag">LightningComponentBundle>
Target Reference
| Target | Where |
lightningCommunity__Page | Experience Builder page (any) |
lightningCommunity__Default | Default community layout |
lightningCommunity__Page_Layout | Page layout region |
Demo Portal Templates
Pre-built patterns for common SE demo scenarios using Experience Cloud.
Customer Self-Service Portal
COMPONENTS NEEDED:
- Hero banner with brand colors and welcome message
- Case submission form (guest-aware)
- Open cases list (authenticated only)
- Knowledge article search
- FAQ accordion
PAGE LAYOUT:
┌──────────────────────────────────────┐
│ Hero: "Welcome to {Brand} Support" │
├──────────────────────────────────────┤
│ Search Bar: "How can we help?" │
├──────────┬───────────────────────────┤
│ My Cases │ Knowledge Articles │
│ (list) │ (card grid) │
├──────────┴───────────────────────────┤
│ FAQ Accordion │
└──────────────────────────────────────┘
DEMO STORY:
"A customer visits the support portal. They search for an answer,
find a knowledge article, but still need help. They submit a case
directly from the portal and track its progress."
Partner Portal
COMPONENTS NEEDED:
- Partner dashboard with KPIs (deal reg, MDF balance, certifications)
- Deal registration form
- Co-branded marketing assets library
- Training/certification tracker
PAGE LAYOUT:
┌──────────────────────────────────────┐
│ Welcome, {Partner Name} │
├────────┬────────┬────────┬───────────┤
│ Deal │ MDF │ Certs │ Pipeline │
│ Regs │Balance │ Status │ Value │
├────────┴────────┴────────┴───────────┤
│ Recent Deal Registrations (table) │
├──────────────────────────────────────┤
│ Marketing Assets | Training │
└──────────────────────────────────────┘
Patient Portal (Health Cloud)
COMPONENTS NEEDED:
- Patient greeting with upcoming appointments
- Care plan progress tracker
- Appointment scheduler
- Secure messaging
- Health record summary
PAGE LAYOUT:
┌──────────────────────────────────────┐
│ Hi {Patient Name} — Next appt: 3/15│
├──────────┬───────────────────────────┤
│ Care │ Upcoming Appointments │
│ Plan │ ┌─────────────────────┐ │
│ Progress│ │ Dr. Smith | Mar 15 │ │
│ (gauge) │ │ Lab Work | Mar 22 │ │
├──────────┴──┴─────────────────────┴──┤
│ Messages (2 unread) │
└──────────────────────────────────────┘
Performance for External Sites
Critical Rendering Path
<class="code-tag">template>
class="code-comment"><!-- Above the fold: render immediately -->
<class="code-tag">div class="hero">
<class="code-tag">h1>{headline}</class="code-tag">h1>
<class="code-tag">p>{subheadline}</class="code-tag">p>
</class="code-tag">div>
class="code-comment"><!-- Below the fold: lazy load -->
<class="code-tag">template if:true={belowFoldVisible}>
<class="code-tag">c-article-grid articles={articles}></class="code-tag">c-article-grid>
</class="code-tag">template>
</class="code-tag">template>
_belowFoldVisible = false;
connectedCallback() {
requestAnimationFrame(() => {
this._belowFoldVisible = true;
});
}
Image Optimization
<class="code-tag">img src={imageUrl}
alt={imageAlt}
loading="lazy"
width="400"
height="300"
class="responsive-img" />
.responsive-img {
width: 100%;
height: auto;
border-radius: var(--slds-g-radius-border-2, 0.25rem);
}
SEO Considerations
- Use semantic HTML:
for page title, for sections, for content blocks
- Add
tags via Head Markup in Experience Builder (not in LWC)
- Use meaningful link text:
View case details not Click here
- Provide alt text on all images
- Structured data (JSON-LD) via Head Markup for articles and FAQs
Scoring Rubric (100 Points)Reference
| Category | Points | Pass Criteria |
| Theme Compliance | 20 | Uses --dxp-* tokens with SLDS fallbacks; no hardcoded brand colors |
| Guest User Handling | 20 | Auth-aware rendering; secure data access; graceful guest CTA |
| Navigation | 15 | Uses NavigationMixin; breadcrumbs; accessible link patterns |
| Experience Builder Config | 15 | Correct targets; configurable properties; sensible defaults |
| Performance | 15 | Lazy loading; optimized images; minimal DOM |
| SEO & Accessibility | 15 | Semantic HTML; alt text; meaningful link text; aria labels |
Cross-Skill IntegrationReference
| Skill | Relationship |
| sf-lwc-design | SLDS 2 hooks used as fallbacks when DXP tokens aren't available |
| sf-lwc-theming | Custom theme creation for Experience Cloud sites |
| sf-lwc-mobile | External sites have high mobile traffic — mobile patterns critical |
| sf-lwc-content | Microcopy must be guest-friendly, no internal jargon |
| sf-se-demo-scripts | Portal templates feed directly into demo flows |