S-Controls cannot be created new and cannot be modernized in place. The migration is per-S-Control: build an LWC equivalent, swap references, retire the original.
- Inventory existing S-Controls
From Setup, search for S-Controls. List every Custom S-Control in the org with its name, body length, and where it is referenced (page layouts, custom buttons, custom tabs).
- Categorize by purpose
Static display panels (lowest effort), API-calling buttons (medium effort), full UI pages (highest effort). Migrate easiest first to build momentum.
- Build equivalent LWC
For each S-Control, write an LWC that does the same thing. Reuse standard SLDS styling, call Apex through AuraEnabled methods, and place on the same locations the S-Control occupied.
- Update page layouts and buttons
Replace the S-Control reference with the LWC. Test the page renders correctly and the LWC behaves like the S-Control did.
- Retire the S-Control
Once all references are swapped, delete the S-Control metadata. Document the migration so successor admins know the LWC is the canonical replacement.
- Repeat across all S-Controls
Work through the backlog. Long-running orgs may have 50 to 100 S-Controls; the migration is project-scale.
- New S-Controls cannot be created in any org after 2010. If you find an S-Control feature you want to extend, the only path is migration.
- S-Controls store full HTML and JavaScript with no security boundary. Any S-Control with API logic is a potential security risk if compromised; audit before retiring.
- Some S-Controls have hard dependencies on Salesforce Classic. LWC migration may require Classic-only behavior simulation; document the gap.
- Custom buttons that fire S-Control JavaScript do not auto-migrate when you build the LWC. Update the button to call the LWC method explicitly.
- Removing an S-Control with active references silently breaks the page. Always swap references first, then delete.