agentleFS
jiten-singh-shahijiten-singh-shahi/salesforce-claude-code/.cursor/skills/sf-visualforce-development/SKILL.md

sf-visualforce-development

Skill15 starsChanged 7 months agoMITView on GitHub

Visualforce development — pages, controllers, extensions, ViewState, JS Remoting, LWC migration. Use when maintaining VF pages, building PDFs, or planning VF-to-LWC migration. Do NOT use for LWC, Aura, or Flow.

The file

We split this skill into the rules it gives an agent

7 rules. About 0 are common, 5 are distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈5

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    When maintaining or extending existing Visualforce pages in production

    line 13
  2. Very specific:

    When building PDF renderable pages (renderAs="pdf") — LWC cannot do this

    line 14
  3. Distinctive:

    When creating custom email templates with complex formatting

    line 15
  4. Distinctive:

    When overriding standard buttons (New, Edit, View) with custom UIs

    line 16
  5. Distinctive:

    When planning and executing migration from Visualforce to LWC

    line 17
  6. Distinctive:

    When debugging ViewState issues or page performance problems

    line 18
  7. Very specific:

    Use {!$RemoteAction.ClassName.methodName} (namespace-safe).

    line 178

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Visualforce Development

Visualforce is Salesforce's server-side rendering framework. While LWC is the modern standard, Visualforce remains heavily used for PDF generation, email templates, custom overrides, and legacy applications.

When to Use

  • When maintaining or extending existing Visualforce pages in production
  • When building PDF renderable pages (renderAs="pdf") — LWC cannot do this
  • When creating custom email templates with complex formatting
  • When overriding standard buttons (New, Edit, View) with custom UIs
  • When planning and executing migration from Visualforce to LWC
  • When debugging ViewState issues or page performance problems

@../_reference/VISUALFORCE_PATTERNS.md


Page Creation Procedure

Step 1 — Choose Controller Type

TypeWhen to Use
Standard ControllerSingle-record CRUD without custom logic
Standard List ControllerList views with built-in pagination
Custom ControllerFull control over logic, data, navigation
Controller ExtensionAdd functionality to standard/custom controllers

Step 2 — Create the Page

<apex:page standardController="Account"
           extensions="AccountOverviewExtension"
           lightningStylesheets="true"
           docType="html-5.0"
           title="Account Overview">
    <apex:pageBlock title="Account Details">
        <apex:pageBlockSection columns="2">
            <apex:outputField value="{!Account.Name}" />
            <apex:outputField value="{!Account.Industry}" />
        </apex:pageBlockSection>
    </apex:pageBlock>
</apex:page>

Step 3 — Custom Controller (if needed)

public with sharing class InvoiceController {
    public List<Invoice__c> invoices { get; private set; }
    public String searchTerm { get; set; }

    public InvoiceController() {
        searchTerm = '';
        loadInvoices();
    }

    public PageReference search() {
        loadInvoices();
        return null; // Stay on same page
    }

    private void loadInvoices() {
        String likeSearch = '%' + String.escapeSingleQuotes(searchTerm) + '%';
        invoices = [
            SELECT Id, Name, Amount__c, Status__c, CreatedDate
            FROM Invoice__c WHERE Name LIKE :likeSearch
            WITH USER_MODE ORDER BY CreatedDate DESC LIMIT 100
        ];
    }
}

Step 4 — Controller Extension (if needed)

public with sharing class AccountOverviewExtension {
    private final Account account;

    // Required constructor signature
    public AccountOverviewExtension(ApexPages.StandardController stdController) {
        if (!Test.isRunningTest()) {
            stdController.addFields(new List<String>{ 'OwnerId', 'AnnualRevenue' });
        }
        this.account = (Account) stdController.getRecord();
    }

    public List<Contact> relatedContacts {
        get {
            if (relatedContacts == null) {
                relatedContacts = [
                    SELECT Id, Name, Email, Phone
                    FROM Contact WHERE AccountId = :account.Id
                    WITH USER_MODE ORDER BY Name LIMIT 50
                ];
            }
            return relatedContacts;
        }
        private set;
    }
}

ViewState Management

ViewState is a hidden, encrypted form field that maintains page state across postbacks. 170KB limit — exceeding it causes a runtime error.

The transient Keyword

Mark variables that do not need to survive postbacks as transient:

public with sharing class ReportController {
    // IN ViewState — needed across postbacks
    public String selectedFilter { get; set; }
    public Integer currentPage { get; set; }

    // NOT in ViewState — recomputed on each request
    transient public List<AggregateResult> reportData { get; private set; }
    transient public Blob chartImage { get; private set; }
}

Reduction Strategies

StrategyImpact
transient keyword on large/recomputable variablesHigh
apex:outputPanel + reRender (partial refresh)Medium
Paginate large data setsHigh
Use JavaScript Remoting (stateless)High
Move read-only data outside apex:formMedium

JavaScript Remoting

Stateless, high-performance Apex calls that bypass ViewState entirely.

Apex Method

@RemoteAction
public static List<Account> findAccounts(String searchTerm) {
    String safeTerm = '%' + String.escapeSingleQuotes(searchTerm) + '%';
    return [
        SELECT Id, Name, Industry FROM Account
        WHERE Name LIKE :safeTerm WITH USER_MODE LIMIT 25
    ];
}

JavaScript Invocation

Visualforce.remoting.Manager.invokeAction(
    '{!$RemoteAction.AccountSearchController.findAccounts}',
    term,
    function(result, event) {
        if (event.status) {
            renderResults(result);
        } else {
            console.error(event.message);
        }
    },
    { escape: true, timeout: 30000 }
);

Use {!$RemoteAction.ClassName.methodName} (namespace-safe). Set escape: true to prevent XSS.


Partial Page Refresh

<apex:actionFunction name="refreshDashboard" action="{!refresh}"
                     reRender="dashPanel" status="loadingStatus" />

<apex:selectList value="{!selectedRegion}" size="1">
    <apex:selectOptions value="{!regionOptions}" />
    <apex:actionSupport event="onchange" action="{!filterByRegion}"
                        reRender="dashPanel" status="loadingStatus" />
</apex:selectList>

<apex:actionStatus id="loadingStatus">
    <apex:facet name="start"><img src="/img/loading.gif" alt="Loading..." /></apex:facet>
</apex:actionStatus>

Migration to LWC

Decision Matrix

Keep VisualforceMigrate to LWC
PDF generation (renderAs="pdf")High-traffic pages needing performance
Email templatesNew feature development
Complex server-state wizardsPages using Apex controller only

Key VF-to-LWC Mappings

VisualforceLWC
apex:pageBlockTablelightning-datatable
apex:commandButton action="{!save}"lightning-button onclick={handleSave} + imperative Apex
apex:inputFieldlightning-input-field (in lightning-record-edit-form)
JavaScript Remoting@wire or imperative Apex import
apex:actionSupportStandard DOM event handlers
{!property} merge fields{property} template expressions

Embedding LWC in Visualforce (Lightning Out)

For incremental migration, embed LWC inside existing VF pages:

<apex:includeLightning />
<div id="lwc-container"></div>
<script>
$Lightning.use("c:lwcOutApp", function() {
    $Lightning.createComponent("c:accountDashboard",
        { recordId: "{!Account.Id}" }, "lwc-container");
});
</script>

Migration Checklist

  1. Inventory — list all VF pages, controllers, usage frequency
  2. Categorize — mark each page as Keep VF / Migrate / Retire
  3. Dependencies — map controller extensions, custom components, static resources
  4. Security audit — review XSS/injection issues before or during migration
  5. Feature parity — replicate all VF functionality in LWC
  6. Test coverage — write LWC Jest tests to match existing Apex test coverage
  7. Incremental rollout — use Lightning Out to embed LWC in VF during transition
  8. Redirect — update links, overrides, navigation to new LWC pages
  9. Deprecate — mark old VF pages as inactive, remove after validation

Related

Guardrails

  • sf-security-constraints — Enforced rules for XSS prevention, SOQL injection, CRUD/FLS enforcement

Agents

  • sf-visualforce-reviewer — For interactive, in-depth Visualforce review guidance

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.