When a custom LWC beats a standard component, and when it doesn’t

Written by

in

Every org I’ve worked on has at least one custom Lightning Web Component that didn’t need to exist. Usually it’s a record highlights panel rebuilt pixel-for-pixel to match a mockup, or a related list reimplemented because someone didn’t like the default row height. Three years later, nobody remembers why it’s custom, and it’s the thing that breaks every release.

The opposite mistake happens too. I’ve seen teams force a genuinely complex screen flow into standard Flow screen components, bolting on formula fields and hidden sections until the logic is unreadable, because “we try to avoid custom code.” Both failures come from the same place: treating the custom-vs-standard call as a style preference instead of an engineering decision.

Start from the default, not the exception

Standard components should win by default. Lightning App Builder components, Dynamic Forms, Flow screen components and the standard related lists get platform upgrades for free, inherit accessibility fixes automatically, and don’t need a developer on hand every time field-level security changes. A junior admin can maintain a page built from standard components. A custom LWC usually needs whoever wrote it, or a very good comment trail, because the logic lives in JavaScript, not in clicks.

So the real question isn’t “can I build this as a custom component.” Almost anything can be built as a custom component. The question is what you’re giving up to do it, and whether what you get back is worth that cost. Most of the time it isn’t.

Where standard components actually fall over

Cross-record logic in a single view

Standard related lists and highlights panels are bound to one record and its direct relationships. The moment you need to pull in data from a grandparent object, aggregate across a child relationship, or show a calculated value that depends on more than a formula field can express, you’ve hit the ceiling. I built a component a while back that showed a rolling 90-day case volume trend against SLA breach count, on the account page, computed from two child objects with different filter criteria. No combination of standard list views and report charts got close, and a custom LWC calling Apex was the only honest answer.

Conditional UI that standard components can’t express

Dynamic Forms handles field-level conditional visibility well. It does not handle “show this entire section, with this specific layout, only when three unrelated conditions are all true and the user has one of two permission sets.” You can hack it with formula fields and record types, and I’ve watched teams spend more hours fighting that hack than the custom component would have taken to build properly.

Inline actions that need immediate feedback

Standard quick actions post back and refresh. If a contact-centre agent needs to trigger an action and see the result in under a second, without a page refresh breaking their flow, a declarative quick action often feels sluggish enough that agents route around it. That’s a real usability cost, not a cosmetic one, and it’s the kind of thing that shows up in average handle time six months later.

What building custom actually costs you

This is the part that gets skipped in the planning meeting. A custom LWC means:

  • Someone owns the Jest test suite, and it has to stay green through every org upgrade
  • Accessibility is now your responsibility, not the platform’s, down to keyboard navigation and screen reader labels
  • Every new field or business rule change is a deployment, not a configuration change an admin can make on a Friday afternoon
  • The component needs its own security review, because it’s making its own SOQL and Apex calls instead of relying on standard field-level security enforcement

None of that is a reason to avoid custom components. It’s a reason to make sure the thing you’re building actually needs to be custom, because that list of costs doesn’t go away just because the component works on day one.

A decision framework that holds up under pressure

When a requirement lands on my desk that looks like it needs a custom component, I run it through four questions before anyone opens VS Code.

Can Dynamic Forms, a Flow screen component, or a standard related list get within 80% of this with configuration alone? If yes, build that first and show the stakeholder. Half the time the remaining 20% turns out to be a nice-to-have, not a requirement.

Does the logic depend on data the platform can’t surface declaratively? Cross-object aggregation, external callouts rendered inline, or calculations too complex for a formula field are the honest triggers for custom code. A preference for a different button colour is not.

Will this component need to change often, and who will change it? If the answer is “the business team, frequently,” lean hard toward standard, even if it means a slightly less polished result today. If it’s “rarely, and only a developer touches it,” custom is a safer bet.

What’s the blast radius if this breaks during a Salesforce release? A standard component degrades gracefully, usually. A custom LWC with an unhandled API version bump can take down a page entirely. If the component sits on a page every agent uses every call, that risk needs to be priced into the decision, not discovered after a Sunday release.

What I actually check in code review

When a pull request adds a new custom LWC, I’m not reviewing whether the code is clean, not first. I’m checking whether the PR description explains why a standard component couldn’t do the job. If that explanation isn’t there, the review stops until it is. That one habit has quietly reduced the amount of unnecessary custom UI across every team I’ve led, more than any architecture guideline ever has.

The components worth building custom are the ones that would be genuinely painful to build any other way. Everything else is a related list with better padding, and the platform already gives you that for free.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *