Page 5 — Building the Core LWC Components

guideCard, guideLibrary, guideArticle, guideEditor

Series: Build a Salesforce Guide App with AI

Page: 5 of 10

Time to complete: 60–90 minutes

Prerequisites: Page 4 complete (Apex deployed and tested)


How Lightning Web Components Work

Each LWC component is a folder containing three files:

  • componentName.html — the template (what renders)
  • componentName.js — the controller (the logic)
  • componentName.css — the styles
  • componentName.js-meta.xml — metadata telling Salesforce where the component can be used

Components talk to each other via Custom Events (child to parent) and @api properties (parent to child). They talk to Apex via @wire (reactive, cached) or imperative calls (on-demand, not cached).

The four core components have this hierarchy:

guideLibrary (manages view state)
  ├── guideCard (individual card in the grid)
  ├── guideArticle (full article reader)
  └── guideEditor (admin authoring form)

guideLibrary is the parent. It decides whether to show the library grid, an article, or the editor. The child components communicate back via events.


The Context-Setting Prompt for Components

Start a new Claude conversation (or continue the same one if it hasn’t been too long) with this context:


💬 Context prompt for LWC phase:

I’m continuing to build a Salesforce Guide Hub app. The Apex service class GuideService is already deployed with these methods: getGuides, getGuideDetail, getTopics, saveGuide, saveVideos, submitForApproval, publishAdminGuide, submitVote, getGuidesForModal, getAdminGuides, getGuidesByTopic.

Now I need to build four Lightning Web Components. Key requirements:

  • Use imperative Apex calls in guideLibrary (not @wire) — @wire caches results and causes stale data bugs with category filtering
  • guideLibrary manages all view state: ‘library’, ‘article’, ‘editor’
  • guideCard fires a ‘select’ CustomEvent with { guideId } payload
  • guideArticle fires ‘back’ and ‘edit’ CustomEvents
  • guideEditor fires ‘saved’ and ‘back’ CustomEvents
  • All components must handle loading, empty, and error states explicitly
  • guideLibrary has an @api isAdmin property — when true, shows the New Guide button

I’m on Windows and will use base64-encoded PowerShell scripts to write the files to avoid copy-paste corruption issues. Please generate complete files — do not truncate.

Please confirm before I ask for the first component.


Building Each Component

Request them in order — guideCard first because guideLibrary depends on it.

guideCard


💬 Prompt:

Build the guideCard LWC component. It:

  • Accepts an @api guide property (a Guide__c record or a Knowledge article object with isKnowledge: true)
  • Shows a category badge with a colour matching the category (Sales=blue, Support=amber, Onboarding=pink, CPQ=green, Data Management=purple, Productivity=slate, General=gray)
  • For Knowledge articles: shows a blue “Knowledge” badge instead, and “Opens in new tab” in the footer
  • Shows title, summary (truncated), read time, and helpful count in the footer
  • On click: fires ‘select’ CustomEvent with { guideId } for guides; navigates to standard__navItemPage Guide_Article with state { c__guideId } for Knowledge articles
  • Uses NavigationMixin for Knowledge navigation
  • Has hover animation (slight lift and shadow)

Generate all four files: html, js, css, js-meta.xml (isExposed: false).


guideLibrary


💬 Prompt:

Build the guideLibrary LWC component. It:

  • Has @api isAdmin property (Boolean, default false)
  • Manages view state: ‘library’, ‘article’, ‘editor’
  • In library view: shows a search input, category filter pills (All/Sales/Support/Onboarding/CPQ/Data Management/Productivity/General), and a card grid using c-guide-card
  • When isAdmin is true: shows a New Guide button
  • Fetches guides AND Knowledge articles in parallel using Promise.all — getGuides + getKnowledgeArticles (imported from GuideService)
  • Knowledge articles are given isKnowledge: true and their Title mapped to Name, Summary to Summary__c
  • Uses CurrentPageReference @wire to read c__guideId from URL state — if present on load, opens article view for that guide
  • handleCategoryClick guard: if clicked category is already active, return immediately (prevents infinite spinner)
  • In article view: renders c-guide-article with record-id and is-admin, handles ‘back’ and ‘edit’ events
  • In editor view: renders c-guide-editor with record-id, handles ‘back’ and ‘saved’ events
  • handleGuideSaved: returns to library, resets search and category, re-fetches

Generate all four files. Use sentence-case labels throughout.


⚠️ Common issue: @wire caching

If Claude uses @wire(getGuides, ...) instead of imperative calls, ask it to rewrite:

“Please rewrite guideLibrary.js to use imperative Apex calls instead of @wire for getGuides. The @wire adapter caches results by parameter — if a category returns empty results once, that empty result is cached and shown even after new guides are published. Use a fetchAll() method called from connectedCallback and whenever search or category changes.”


guideArticle


💬 Prompt:

Build the guideArticle LWC component. It:

  • Has @api recordId and @api isAdmin properties
  • Uses @wire getGuideDetail to fetch the guide
  • Renders: category badge (with colour matching category), title, metadata row (read time, version, last updated date), summary, body using lightning-formatted-rich-text
  • Videos: the guide has Video_Position__c (Top/After Introduction/Bottom) and a Guide_Videos__r subquery. Render videos at the correct position. Each video is passed to a c-video-block child component.
  • Sidebar: shows category, helpful count, and topic tags (from Topic_Assignments__r subquery)
  • Helpful voting: Yes/No buttons. On click, calls submitVote() Apex method optimistically (updates UI immediately, then fires Apex in background)
  • When isAdmin is true: shows an Edit Guide button that fires ‘edit’ CustomEvent with { guideId }
  • Back button fires ‘back’ CustomEvent
  • White background on the article container (not transparent — it should not inherit the page background colour)

Generate all four files.


videoBlock

This is a small child component used by guideArticle.


💬 Prompt:

Build a small videoBlock LWC child component used inside guideArticle. It accepts @api video (a Guide_Video__c record).

  • If Video_Type__c is YouTube or Vimeo: render a responsive 16:9 iframe wrapper with the embed URL
  • If Video_Type__c is External Link: render a styled link card with a link icon, the video Name, and a new_window icon. Opens in new tab.
  • If Video_Type__c is Salesforce File: render a dark thumbnail card with a play button circle in the centre, the video Name below it, and “Click to play · Opens in new tab” hint text. Links to /apex/GuideVideoPlayer?contentDocumentId={Video_URL__c}
  • Optional description shown above the video if present

isExposed: false. Generate all four files.


guideEditor


💬 Prompt:

Build the guideEditor LWC component. It:

  • Has @api recordId (null for new guide, populated when editing)
  • Uses @wire getGuideDetail to pre-populate when editing
  • Uses @wire getTopics to populate the topic dual listbox
  • Form fields: Title (required), Summary (textarea), Category (combobox), Audience (combobox: User/Admin), Read Time, Tags, Body (lightning-input-rich-text), Topics (lightning-dual-listbox)
  • Video section: Add Video button that adds a row with URL input and description input. URL auto-detects type (YouTube/Vimeo/SF File starting with 069/External Link) and shows a colour-coded type badge. Remove button per row.
  • Video Position combobox (Top/After Introduction/Bottom)
  • Three action buttons at the bottom:
    • Cancel (fires ‘back’ event)
    • Save as Draft (saves guide + videos, shows success toast, STAYS on editor)
    • When Audience = User: Submit for Approval (saves, submits, fires ‘saved’ event returning to library)
    • When Audience = Admin: Publish Now (saves, calls publishAdminGuide, fires ‘saved’ event)
  • buildRecord() must include Is_Active__c: true — field defaults don’t apply to Apex upserts

Generate all four files.


Deploying the Components

Ask Claude to generate a PowerShell deployment script for all the components at once:


💬 Prompt:

Generate a PowerShell script that writes all five LWC components (guideCard, guideLibrary, guideArticle, videoBlock, guideEditor) to my project at C:\Users[username]\Desktop\guide-hub\force-app\main\default\lwc.

Base64-encode all file content. Use [System.IO.File]::WriteAllBytes(). Create the component directories with New-Item -ItemType Directory -Force before writing files. Print a success message when done.


Download, unblock, run:

Unblock-File -Path .\write-lwc.ps1
.\write-lwc.ps1
sf project deploy start --source-dir force-app/main/default/lwc

Common Deployment Errors

LWC1503: Parsing error: Expecting Unicode escape sequence A $ in a @wire decorator got escaped. In guideLibrary.js, the wire adapter uses reactive properties like '$searchTerm' and '$activeCategory'. If these get mangled, ask Claude to regenerate the file.

Unable to find Apex action method referenced as 'GuideService.methodName' The LWC references a method that doesn’t exist in the deployed Apex. Check the method name matches exactly. Remember Apex is case-sensitive on the JavaScript side.

The 'propertyName' property doesn't exist on the component A meta.xml file declares a property that the JS doesn’t have an @api declaration for. Usually a leftover from a previous version of the component. Check the meta.xml against the JS.


Check Your Work

  • ✅ All five components deploy without errors
  • ✅ Components appear in Setup → Custom Code → Lightning Components
  • ✅ No errors in the VS Code Problems panel

Move to Page 6 — wiring everything together in Lightning App Builder.