本文へ移動
cccskills
無料GitHub で公開

custom-button-to-action-migration

Migrating Classic Custom Buttons (Detail Page Buttons, List Buttons, Mass Action Buttons) and JavaScript Buttons to Lightning Quick Actions, Screen Flow Actions, LWC Quick Actions, and headless Quick Actions. Covers JavaScript-button-to-action translation patterns (sforce.apex.execute → Apex action, navigation alerts → toast events, MassAction.update → record-collection processing), URL button translation, and the irreversible loss of Classic JavaScript button capability in Lightning. NOT for new Quick Action design (use admin/global-actions-and-quick-actions) or Lightning record page composition (use admin/lightning-app-builder-advanced).

インストール方法を見る

含まれるファイル(7)

  • SKILL.md21.3 KB
  • references/examples.md9.8 KB
  • references/gotchas.md8.2 KB
  • references/llm-anti-patterns.md7.2 KB
  • references/well-architected.md6.9 KB
  • scripts/check_custom_button_to_action_migration.py4.7 KB
  • templates/custom-button-to-action-migration-template.md3.1 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Custom Button to Action Migration

This skill activates when a practitioner needs to migrate Classic Custom Buttons (especially JavaScript buttons, which are not supported in Lightning Experience) to Lightning Quick Actions, Screen Flow Actions, LWC Quick Actions, or other Lightning-native action surfaces.


Before Starting

Gather this context before working on anything in this domain:

  • Inventory all custom buttons across all objects. Tooling API: SELECT Id, Name, EntityDefinition.QualifiedApiName, BehaviorType, ContentSource FROM WebLink. BehaviorType includes Detail, List, Mass; ContentSource includes URL, OnClickJavaScript, VisualforcePage, S Control.
  • For each JavaScript button, capture the full OnClick JavaScript. The migration is heavily dependent on what the JS does — read each button before designing replacements.
  • Confirm whether each button is currently invoked: usage data via WebLink is limited; consider deploying lightweight tracking (custom field on the user profile or feature consumption events) BEFORE deprecating to confirm low-usage buttons can be retired without replacement.
  • Confirm Lightning UI is the primary user surface. JavaScript buttons continue to work in Salesforce Classic; if the org has both Classic and Lightning users, retain the Classic button and ADD a Lightning replacement (don't remove the Classic button if Classic users still need it).
  • For URL buttons, confirm whether the linked URL is a relative Salesforce path (often broken in Lightning) or an absolute external URL (usually works as-is).

Core Concepts

1. Classic Button Type → Lightning Replacement

Classic Button TypeContentLightning ReplacementMigration Difficulty
Detail Page Button — URL (relative path)/apex/MyVfPage?id={!Account.Id}Quick Action with Visualforce override OR navigation Quick ActionLow
Detail Page Button — URL (absolute external)https://external.com/lookup?id={!Account.Id}Quick Action with URL action type, or LWC Quick Action with window.openLow
Detail Page Button — JavaScript (simple Apex call)sforce.apex.execute('MyController','myMethod', {id: '{!Id}'})LWC Quick Action calling imperative ApexMedium
Detail Page Button — JavaScript (complex DOM manipulation)var elem = document.getElementById(...); elem.style...Re-architect as Screen Flow with Display fields OR LWC Quick ActionHigh
Detail Page Button — Visualforce Page overrideCustom VF pageQuick Action with Lightning component override OR retained as VFMedium
List Button — URL (relative)URL navigates to a list-context pageList View Action OR Mass Quick ActionMedium
List Button — JavaScript (operates on selected records)Reads getRecordIds() and processesMass Quick Action invoking Apex/Flow with selected record IDsHigh
Mass Action ButtonOperates on multiple records from a list viewMass Quick Action OR List View Action invoking Flow/ApexHigh
S-Control buttonsLegacy S-ControlNOT supported anywhere in modern Lightning; rebuild from scratchHigh

2. JavaScript Buttons Have NO Direct Lightning Equivalent

Salesforce explicitly does not support JavaScript Buttons in Lightning Experience. The button definition still exists in metadata (and continues to work in Classic), but in Lightning UI it does not render or fires only an "unsupported" message.

Classic JS PatternLightning Replacement
alert('Saved')ShowToastEvent from lightning/platformShowToastEvent
confirm('Delete?') then conditional logicLightningConfirm from lightning/confirm
window.location.href = '/...'NavigationMixin.Navigate({type: 'standard__webPage', attributes: {url: '...'}})
sforce.apex.execute('Class', 'method', params)Imperative Apex import + await method({...})
sforce.connection.update(records)import { updateRecord } from 'lightning/uiRecordApi' OR @AuraEnabled Apex with explicit DML
getRecordIds() (list buttons)@api recordIds exposed by Mass Quick Action / List Action
document.getElementById(...) DOM manipulationLWC this.template.querySelector(...) (within own component only)

3. Three Lightning Action Surfaces

Action TypeWhen to useFiles / Components
Quick Action — Create / Update / Log a CallStandard CRUD or activity loggingSetup configuration only; no code
Screen Flow ActionMulti-step user input, branching logic, no codeFlow Builder; deploy as Flow
LWC Quick Action (screen)Custom UI for input + Apex processingLWC bundle with lightningRecordPage Quick Action target
LWC Quick Action (headless)One-click action with no UI (just Apex + toast)LWC with actionType set to Action and headless invocation
Aura Quick ActionLegacy; only when LWC is insufficient (rare)Aura component bundle

LWC Quick Actions are the modern preferred replacement for most non-trivial JavaScript buttons. Headless LWC Quick Actions specifically replace the "click button → confirmation alert → save" pattern.

4. List View / Mass Action Replacement

Classic PatternLightning Replacement
List Button with JS that loops over getRecordIds()Mass Quick Action that exposes @api recordIds to an LWC, which iterates and calls Apex
Mass Action Button (e.g., "Mass Update Status")List View Action invoking a Screen Flow that takes the record collection as input
Custom Mass Action with complex UILWC List Action with internal logic
List Button that just navigates to a URLList View URL Action (Lightning supports URL list actions)

5. URL Button Translation Pitfalls

URL buttons in Lightning handle absolute external URLs cleanly. Relative paths break:

Classic URL PatternLightning Behavior
/apex/MyVfPage?id={!Account.Id}Lightning rewrites to /lightning/cmp/... — sometimes works, often doesn't
/{!Account.Id} (record navigation)Use NavigationMixin instead
/{!Account.Id}/d (record detail in Classic)Lightning has no "detail mode" URL convention
Absolute external URLWorks as-is in both surfaces
URL with target="_self" vs _blankWindow-target hints not always honored in Lightning

For relative paths, replace with a Quick Action that uses the Lightning navigation framework, not a URL.


Common Patterns

Pattern 1: JavaScript Button That Calls Apex → Headless LWC Quick Action

When to use: A Classic JS button that calls an Apex method, shows a confirmation/result, and refreshes the page. This is the most common JS button pattern.

How it works:

  1. Identify the Apex class and method the JS button calls.
  2. Convert the Apex method to @AuraEnabled (typically NOT cacheable since it performs side effects).
  3. Build an LWC Quick Action with actionType=Action (headless mode) and target lightning__RecordAction.
  4. The LWC's invoke() method calls the Apex imperatively, fires a toast for success/error, and dispatches RefreshRecordEvent from @salesforce/apex to refresh the page.
  5. Configure the Quick Action in Setup → Object Manager → Buttons, Links, and Actions.
  6. Add the Quick Action to the page layout (Lightning Actions section).

Why not the alternative: Screen Flow is also a valid replacement but adds a UI step (typically a confirmation screen) that users may not want for a simple "do it now" action.

Pattern 2: JavaScript Button with User Input → Screen Flow

When to use: A Classic JS button that prompts for input (a prompt() or a custom HTML form) and processes the result.

How it works:

  1. Build a Screen Flow with the input fields the button collected.
  2. Add an Action (Apex Invocable, Update Records, etc.) for the processing logic.
  3. Configure as a Screen Flow Quick Action on the object.
  4. Optional: add a confirmation screen for user feedback.

Why not the alternative: Building a custom LWC for a simple input form is overkill when Screen Flow handles it declaratively.

Pattern 3: JavaScript List Button → Mass Quick Action with LWC

When to use: A Classic JS list button that processes selected records via getRecordIds().

How it works:

  1. Build an LWC component targeted at lightning__RecordAction with actionType=ScreenAction.
  2. Expose @api recordIds (set automatically when invoked from a list).
  3. The LWC's invoke() method (or the connectedCallback if always invoked once mounted) iterates this.recordIds and calls Apex with the collection.
  4. Handle partial successes — some records may fail processing.
  5. Configure as a List View Action in Setup.

Why not the alternative: Direct Apex Invocable Action from a Flow can also work, but loses the per-record progress UI an LWC can provide.

Pattern 4: URL Button to External System → Lightning URL Action

When to use: A Classic button that opens an external system URL with merge field substitution (e.g., a LinkedIn lookup, a CTI dial-out, a partner portal SSO).

How it works:

  1. In Setup → Object Manager → Buttons, Links, and Actions, create a new Action with type "Custom Visualforce" or "URL".
  2. Set the URL with merge fields: https://external.com/lookup?id={!Account.Id}&name={!Account.Name}.
  3. Configure target window behavior (open in new tab vs replace current).
  4. Add to the page layout.

Why not the alternative: For a simple URL navigation, an LWC Quick Action is overkill — URL Actions handle this natively.

Pattern 5: Coexistence — Retain Classic Button, Add Lightning Action

When to use: The org has both Classic and Lightning users. Removing the Classic button breaks Classic users; not adding the Lightning equivalent breaks Lightning users.

How it works:

  1. Keep the Classic Custom Button as-is (works in Classic).
  2. Build the Lightning Quick Action / LWC Quick Action / Screen Flow Action equivalent.
  3. Both surface independently per UI mode.
  4. Eventually, when all users are on Lightning, retire the Classic button.

Why not the alternative: Removing the Classic button before all users have moved to Lightning breaks production for Classic users immediately. Coexistence is the safe path during the transition window.


Decision Guidance

SituationRecommended ApproachReason
Classic JS button, calls Apex, shows alertPattern 1: Headless LWC Quick ActionClosest UX parity for one-click actions
Classic JS button, prompts for inputPattern 2: Screen FlowDeclarative input collection; no LWC needed
Classic JS list button, processes selected recordsPattern 3: Mass Quick Action with LWCHandles record-collection processing with progress UI
Classic URL button, external systemPattern 4: Lightning URL ActionNative URL action; no code
Classic URL button, relative Salesforce pathQuick Action with NavigationMixinRelative paths often broken; explicit navigation is safer
Visualforce page override buttonQuick Action with VF override OR retain as VFSome VF overrides have no Lightning equivalent
S-Control buttonsRebuild from scratchS-Controls are fully retired
Classic and Lightning both in usePattern 5: CoexistenceDon't break Classic users prematurely
JS button does complex DOM manipulationLWC Quick Action with internal DOM logicDOM access scoped to the LWC's own template
Mass action operates on >50 recordsInvocable Apex via Mass Action with batch considerationLarge collections may need async processing
Button only used in Salesforce MobileCheck mobile-Quick-Action support per patternSome patterns (LWC headless) work on mobile, others don't

Recommended Workflow

Step-by-step instructions for an AI agent or practitioner working on this task:

  1. Inventory custom buttons. Run the Tooling API query for WebLink. Group by BehaviorType and ContentSource. Read each JS button's OnClick body and capture what it does (Apex call, navigation, alert, DOM manipulation).
  2. Categorize each button by pattern. Apply the Decision Guidance table. Most JS buttons fall into Pattern 1 (Apex call) or Pattern 2 (input prompt). URL buttons usually map cleanly to Pattern 4.
  3. Audit usage. Confirm which buttons are actively used. Buttons that haven't been invoked in 6+ months should be retired without replacement (validated with the user-team).
  4. Build the Lightning replacements. Implement per-pattern. Test each against the same scenarios the original button served.
  5. Configure on page layouts and list views. Each Lightning Action must be added to relevant page layouts (Lightning Actions section) or list view button bars.
  6. Test in sandbox with users from each affected profile. Specifically: do users find the new action where they expect it? Does the action's UX match the original's intent?
  7. Phased production rollout with audit log. Coexistence first (keep Classic, add Lightning); monitor adoption via the Last_Action_Source__c field. Maintain a Custom_Button_Migration_Log__c mapping (Classic name → Lightning replacement → status). Retire Classic buttons when adoption hits the agreed threshold (typically ≥95% Lightning over 30 days).

Review Checklist

Run through these before marking work in this area complete:

  • Every Classic Custom Button has a documented decision: replaced (with what), retained for Classic only, or retired
  • JavaScript buttons that called Apex have been replaced with Headless or Screen LWC Quick Actions (or Screen Flow)
  • URL buttons with absolute external URLs are mapped to Lightning URL Actions
  • URL buttons with relative Salesforce paths are mapped to NavigationMixin-based Quick Actions
  • List buttons that processed selected records have been replaced with Mass Quick Actions
  • All Lightning replacements are added to relevant page layouts and list views
  • User-acceptance testing: representative users from each affected profile confirm the action is discoverable and works as expected
  • Mobile testing: any action that should work in Salesforce Mobile App has been verified on a real mobile device
  • Coexistence period: original Classic button remains in place during the transition for Classic users
  • Audit log of original button → Lightning replacement is committed to source control
  • Apex methods called from Lightning replacements are @AuraEnabled with appropriate with sharing and FLS enforcement

Salesforce-Specific Gotchas

Non-obvious platform behaviors that cause real production problems:

  1. JavaScript buttons silently render as nothing in Lightning Experience. A user navigating Lightning sees the button's place in the page layout — but the button doesn't render. There's no error message, no "this button isn't supported" indicator. Users assume the action is missing entirely. Audit page layouts for JS buttons and either replace them or flag to users that they're Classic-only.

  2. Mass Action limit on records is 200 by default. A list view Mass Action that operates on selected records is governor-limited. Selecting 500 records and invoking a Mass Action processes only the first 200. Users notice silently (the unselected 300 just don't get the action applied). For Mass Actions on larger collections, design a Flow with batch processing or an async Apex job.

  3. {!Account.Id} URL merge fields don't work the same way in all Lightning Action types. Lightning URL Actions support some merge fields, but the {!Object.Field} syntax differs from the Classic Custom Button merge field syntax in subtle ways. Quick Actions of type "URL" use a slightly different merge syntax than Classic. Test each merge field after migration.

  4. Quick Actions invoked from a Console subtab don't navigate the same way as standard Lightning. In Service Cloud Console, a Quick Action that uses NavigationMixin.Navigate({type: 'standard__recordPage'}) opens the navigation in the console workspace — sometimes as a new tab, sometimes replacing the current tab, depending on the action's launch context. If the original button assumed a specific navigation behavior, test in Console mode explicitly.

  5. List View Actions don't appear if the list view filter doesn't match any records. A Mass Quick Action requires at least one selectable record. Empty list views hide the action entirely. Users assume the action is missing for that list view, when actually no records match the filter.

  6. window.opener and cross-window communication patterns from Classic JS don't translate. Some Classic JS buttons opened a popup window, then communicated back to the parent via window.opener.location.reload(). LWC and Lightning Quick Actions have no equivalent — windows are sandboxed differently. Re-architect these flows as Quick Actions that complete in the same context (no popups).

  7. PageReference redirects from Classic Apex callbacks don't work in Lightning Quick Actions. A Classic JS button that called sforce.apex.execute and the Apex method returned a PageReference — Classic followed the redirect. In Lightning, the redirect is ignored. Re-architect: Apex returns data; LWC explicitly navigates via NavigationMixin after the call resolves.

  8. Hard-coded record IDs in JS buttons don't translate to merge fields cleanly. Some JS buttons hardcoded record IDs (anti-pattern) for "demo" records or admin actions. The migration is the moment to remove the hardcoded IDs (use Custom Settings, Custom Metadata, or proper record-context resolution). Quick Actions and Flows have no equivalent for "always operate on record X regardless of context."


Output Artifacts

ArtifactDescription
Lightning Quick ActionsObject-specific actions replacing Detail Page Buttons
LWC Quick Actions (Headless / Screen)Replacements for JS buttons that need Apex execution and/or custom UI
Screen Flow ActionsReplacements for JS buttons that need user input or branching
List View Actions / Mass Quick ActionsReplacements for List Buttons that operate on selected records
URL ActionsReplacements for URL buttons with absolute external URLs
Updated page layoutsLightning Actions section configured to expose new Quick Actions
Migration audit logOld button → new action mapping with status (Active, Retained, Retired)
Coexistence retention listClassic buttons kept for Classic users with a planned retirement date

Related Skills

  • admin/global-actions-and-quick-actions — Use for new Quick Action / Global Action design (post-migration)
  • lwc/lwc-quick-actions — Use for designing LWC Quick Actions in detail (Headless vs Screen)
  • flow/screen-flows — Use for designing Screen Flow Actions
  • lwc/visualforce-to-lwc-migration — Use when buttons reference Visualforce pages being migrated
  • apex/apex-security-patterns — Use when Apex methods called from new Quick Actions need their sharing keyword and CRUD/FLS enforcement designed correctly
  • admin/lightning-app-builder-advanced — Use for placing Quick Actions on Lightning Record Pages

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Use this skill when writing test-first, behavior-driven acceptance criteria in Given/When/Then format for a Salesforce user story. Covers happy path, edge cases, negative paths, permission boundaries, and data-state preconditions so the AC block can drive UAT scripts and Apex test design downstream. Trigger keywords: given when then, gherkin, behavior driven AC, test first acceptance criteria, scenario outline, BDD acceptance criteria. NOT for the user-story format itself (use admin/user-story-writing-for-salesforce). NOT for UAT script writing (use admin/uat-test-case-design). NOT for Apex test method generation (use agents/test-class-generator). NOT for high-level UAT planning (use admin/uat-and-acceptance-criteria). More triggers: acceptance criteria record, ac_id, req_id on a criterion, artefact under test, negative case for a rule-type requirement, no-match fall-through criterion, oracle for a Then clause, test type apex flow manual, criteria linter, check_ac_format.py, --manifest-dir.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Task and Event objects: polymorphic WhatId/WhoId, Activity object model, ActivityHistory vs OpenActivity, activity timeline customization, bulk task creation, Einstein Activity Capture boundaries. NOT for turning on EAC or calendar sync — use admin/einstein-activity-capture-setup. NOT for Email-to-Case — use admin/case-management-setup. Covers ActivitiesSettings metadata, enableActivities, shared Task/Event custom fields and FLS, TaskStatus value sets, Shared Activities and TaskRelation/EventRelation, recurring and child activities, and partial-success bulk DML on Task.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Design Invocable Apex actions that return deterministic, agent-friendly errors instead of surfacing raw exceptions to the LLM. NOT for authoring the action itself — @InvocableMethod schema, labels, security context — use agentforce/custom-agent-actions-apex. NOT for the Apex tests that force each error branch — use agentforce/agent-action-unit-tests.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Use when designing how an Agentforce agent extracts structured input parameters (slots) from a user's natural-language utterance to invoke an action. Triggers: 'agent extract date from user', 'agent action argument extraction', 'agentforce slot filling', 'agent invocable input mapping', 'agent fails to fill required parameter'. NOT for action authoring (use agentforce/agent-actions) or for prompt-template variable binding (use agentforce/prompt-builder-templates).

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Apex test patterns for @InvocableMethod agent actions: per-reason-code branch coverage, bulk safety, callout mocking, deterministic assertions. NOT for testing whether the agent routes to the right topic or answers well — use agentforce/agent-testing-and-evaluation. NOT for designing the error envelope the tests assert on — use agentforce/agent-action-error-handling.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

Designing or reviewing Agentforce actions: Flow actions, Apex invocable actions, prompt-template actions, action naming, input and output contracts, confirmation requirements, and safe error behavior. Triggers: 'agent actions', 'build an agent that can look up an order', 'make the agent able to check order status', 'give the agent a capability', 'agent that can retrieve a record', 'flow action for agent', 'agent invocable action', 'action schema design'. NOT for writing the Apex class itself — use agentforce/custom-agent-actions-apex. NOT for the reason_code error envelope that stops an agent retry loop — use agentforce/agent-action-error-handling.

日本語の概要は準備中です。原文の説明を表示しています。

PranavNagrecha/AwesomeSalesforceSkills192026年10月4日 更新

PranavNagrecha のスキルをすべて見る

このスキルの問題を報告する