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/quick-actions-and-flow-actions) or Lightning record page composition (use admin/lightning-app-builder-advanced).
Best use case
custom-button-to-action-migration is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
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/quick-actions-and-flow-actions) or Lightning record page composition (use admin/lightning-app-builder-advanced).
Teams using custom-button-to-action-migration should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/custom-button-to-action-migration/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How custom-button-to-action-migration Compares
| Feature / Agent | custom-button-to-action-migration | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
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/quick-actions-and-flow-actions) or Lightning record page composition (use admin/lightning-app-builder-advanced).
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# 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 Type | Content | Lightning Replacement | Migration Difficulty |
|---|---|---|---|
| Detail Page Button — URL (relative path) | `/apex/MyVfPage?id={!Account.Id}` | Quick Action with Visualforce override OR navigation Quick Action | Low |
| 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.open` | Low |
| Detail Page Button — JavaScript (simple Apex call) | `sforce.apex.execute('MyController','myMethod', {id: '{!Id}'})` | LWC Quick Action calling imperative Apex | Medium |
| Detail Page Button — JavaScript (complex DOM manipulation) | `var elem = document.getElementById(...); elem.style...` | Re-architect as Screen Flow with Display fields OR LWC Quick Action | High |
| Detail Page Button — Visualforce Page override | Custom VF page | Quick Action with Lightning component override OR retained as VF | Medium |
| List Button — URL (relative) | URL navigates to a list-context page | List View Action OR Mass Quick Action | Medium |
| List Button — JavaScript (operates on selected records) | Reads `getRecordIds()` and processes | Mass Quick Action invoking Apex/Flow with selected record IDs | High |
| Mass Action Button | Operates on multiple records from a list view | Mass Quick Action OR List View Action invoking Flow/Apex | High |
| S-Control buttons | Legacy S-Control | NOT supported anywhere in modern Lightning; rebuild from scratch | High |
### 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 Pattern | Lightning Replacement |
|---|---|
| `alert('Saved')` | `ShowToastEvent` from `lightning/platformShowToastEvent` |
| `confirm('Delete?')` then conditional logic | `LightningConfirm` 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 manipulation | LWC `this.template.querySelector(...)` (within own component only) |
### 3. Three Lightning Action Surfaces
| Action Type | When to use | Files / Components |
|---|---|---|
| Quick Action — Create / Update / Log a Call | Standard CRUD or activity logging | Setup configuration only; no code |
| Screen Flow Action | Multi-step user input, branching logic, no code | Flow Builder; deploy as Flow |
| LWC Quick Action (screen) | Custom UI for input + Apex processing | LWC 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 Action | Legacy; 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 Pattern | Lightning 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 UI | LWC List Action with internal logic |
| List Button that just navigates to a URL | List 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 Pattern | Lightning 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 URL | Works as-is in both surfaces |
| URL with `target="_self"` vs `_blank` | Window-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
| Situation | Recommended Approach | Reason |
|---|---|---|
| Classic JS button, calls Apex, shows alert | Pattern 1: Headless LWC Quick Action | Closest UX parity for one-click actions |
| Classic JS button, prompts for input | Pattern 2: Screen Flow | Declarative input collection; no LWC needed |
| Classic JS list button, processes selected records | Pattern 3: Mass Quick Action with LWC | Handles record-collection processing with progress UI |
| Classic URL button, external system | Pattern 4: Lightning URL Action | Native URL action; no code |
| Classic URL button, relative Salesforce path | Quick Action with NavigationMixin | Relative paths often broken; explicit navigation is safer |
| Visualforce page override button | Quick Action with VF override OR retain as VF | Some VF overrides have no Lightning equivalent |
| S-Control buttons | Rebuild from scratch | S-Controls are fully retired |
| Classic and Lightning both in use | Pattern 5: Coexistence | Don't break Classic users prematurely |
| JS button does complex DOM manipulation | LWC Quick Action with internal DOM logic | DOM access scoped to the LWC's own template |
| Mass action operates on >50 records | Invocable Apex via Mass Action with batch consideration | Large collections may need async processing |
| Button only used in Salesforce Mobile | Check mobile-Quick-Action support per pattern | Some 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
| Artifact | Description |
|---|---|
| Lightning Quick Actions | Object-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 Actions | Replacements for JS buttons that need user input or branching |
| List View Actions / Mass Quick Actions | Replacements for List Buttons that operate on selected records |
| URL Actions | Replacements for URL buttons with absolute external URLs |
| Updated page layouts | Lightning Actions section configured to expose new Quick Actions |
| Migration audit log | Old button → new action mapping with status (Active, Retained, Retired) |
| Coexistence retention list | Classic buttons kept for Classic users with a planned retirement date |
---
## Related Skills
- `admin/quick-actions-and-flow-actions` — Use for new Quick Action / Flow Action design (post-migration)
- `lwc/lwc-quick-actions` — Use for designing LWC Quick Actions in detail (Headless vs Screen)
- `flow/screen-flow-patterns` — Use for designing Screen Flow Actions
- `lwc/visualforce-to-lwc-migration` — Use when buttons reference Visualforce pages being migrated
- `apex/apex-rest-and-aura-enabled` — Use when Apex methods called from new Quick Actions need to be designed correctly
- `admin/lightning-app-builder-advanced` — Use for placing Quick Actions on Lightning Record PagesRelated Skills
transaction-security-policies
Transaction Security policy creation and configuration: condition builder, enhanced policies, enforcement actions (block, MFA, notification, end session), real-time monitoring mode, and policy troubleshooting. NOT for Event Monitoring log analysis or Shield Event Monitoring setup (use event-monitoring). NOT for Apex testing or debug-log analysis.
customer-data-request-workflow
Implement GDPR/CCPA data subject rights (access, deletion, rectification) using Salesforce Privacy Center and/or custom workflow. NOT for general backup or org-level data retention policy.
vlocity-to-native-omnistudio-migration
Use when migrating an org from the Vlocity managed package (vlocity_ins, vlocity_cmt, vlocity_ps) to native OmniStudio. Trigger keywords: Vlocity to OmniStudio migration, namespace migration, vlocity_ins to omnistudio, OmniStudio Migration Tool, DataRaptor namespace update, OmniScript JSON export, managed package to native. NOT for new OmniStudio setup in greenfield orgs, nor for migrating between OmniStudio-native orgs, nor for Salesforce CPQ to Industries CPQ migration.
omnistudio-remote-actions
Use when configuring, troubleshooting, or choosing between Remote Action types in OmniScript or FlexCard. Triggers: 'remote action', 'OmniScript action', 'IP action', 'Apex action element', 'VlocityOpenInterface2', 'Send/Response JSON Path'. NOT for Integration Procedure internal design (use integration-procedures) or generic Apex callout patterns (use apex integration skills).
omnistudio-lwc-omniscript-migration
Migrate classic Visualforce-based OmniScripts to LWC-based runtime with feature parity and regression testing. NOT for new OmniScript design.
omnistudio-custom-lwc-elements
Creating and integrating custom Lightning Web Components within OmniScripts: LWC override patterns, pubsub event handling, custom validation, OmniStudio data passing conventions. Use when a standard OmniScript element cannot meet a UX requirement. NOT for standalone LWC development (use lwc/* skills). NOT for Integration Procedures (use integration-procedures). NOT for embedding an OmniScript inside an LWC (use omnistudio-lwc-integration).
visualforce-to-lwc-migration
Migrating Visualforce pages and components to Lightning Web Components: controller-to-Apex-method translation, viewstate replacement, custom URL parameter handling, PageReference-to-NavigationMixin mapping, Lightning Out coexistence, and inline VF retention strategy. NOT for new LWC development from scratch (use lwc-fundamentals) or Aura-to-LWC migration (use aura-to-lwc-migration).
lwc-quick-actions
Use when building a Lightning Web Component that runs from a record page quick-action button — either a screen action that renders UI in a modal or a headless action that invokes logic with no UI. Triggers: 'lwc quick action on record page', 'headless quick action no ui', 'closeactionscreenevent not working', 'how to pass recordid into quick action lwc', 'quick action vs flow action', 'quick action modal size'. NOT for Flow screen components — use `lwc-in-flow-screens` — and NOT for global actions without a record context or for list-view bulk actions that do not receive a single `recordId`.
lwc-locker-to-lws-migration
Migrating LWCs from Lightning Locker Service to Lightning Web Security (LWS) — flipping the org switch safely, identifying components likely to break, removing Locker workarounds that are now insecure, and validating third-party libraries that previously failed under SecureWindow/SecureElement proxies. NOT for Aura → LWC migration — see lwc/aura-to-lwc-migration. NOT for general LWC security review (XSS, public-API hardening) — see lwc/lwc-security and lwc/lwc-public-api-hardening.
lwc-custom-lookup
Custom lookup component in LWC — typeahead/autocomplete that searches records via Apex SOSL/SOQL, shows pills, supports keyboard navigation, and manages open/close state. Use when lightning-input-field or lightning-record-picker won't work (cross-org search, computed filters, custom result rendering). NOT for in-form lookups inside lightning-record-edit-form (use lightning-input-field) or lookup filters (use admin lookup filter config).
lwc-custom-event-patterns
When and how to design CustomEvent traffic out of an LWC — bubbles / composed / cancelable flag choices, detail payload shape, naming rules, and propagation control. Trigger keywords: 'event not reaching parent', 'composed shadow DOM', 'CustomEvent detail mutation', 'stopPropagation vs stopImmediatePropagation'. NOT for parent-to-child communication (use `@api` — see `lwc/component-communication`), NOT for sibling fan-out (use Lightning Message Service — see `lwc/lightning-message-service`), NOT for wire-service data plumbing.
lwc-custom-datatable-types
Use when you need to extend `lightning-datatable` with custom cell renderings: status pills, progress bars, image thumbnails, action cells, editable pickliststo, rich-text, or any column that `lightning-datatable` does not ship out of the box. Triggers: 'custom cell type lightning datatable', 'progress bar column', 'image column', 'inline edit picklist in datatable', 'rich text column'. NOT for basic datatable usage (see `lwc-data-table`) and NOT for tree-grid or large-dataset virtualization (see `virtualized-lists`).