← Back to Blogs Developer

Wrapper Class in Salesforce Apex: Simple Explanation with Real Examples

content image

When building UIs in Salesforce — whether in Visualforce, Aura, or LWC — you often need to display or process data that doesn't fit neatly into a single Salesforce object. That's exactly what Wrapper Classes solve. A Wrapper Class is a custom Apex class that acts as a container, bundling multiple objects, calculated fields, or UI-specific properties into one clean structure. In this guide, we'll cover what wrapper classes are, why they're used, and walk through three practical examples to make it crystal clear.

📌 What Is a Wrapper Class?

A Wrapper Class is a regular Apex class whose sole purpose is to hold multiple pieces of data together — data that may come from different Salesforce objects or may not exist on any object at all. Think of it as a custom container you design yourself.

A real-life analogy: imagine an online shopping cart. In the database, a Product only has a Name and a Price. But your cart UI needs to show the product name, price, quantity, total price, and a checkbox to select items. None of those extra fields live on the Product object. A Wrapper Class acts like the cart itself — it holds all of that information together in one place for the UI to consume.

❓ Why Use Wrapper Classes?

ScenarioWhy a Wrapper Helps
Display multiple objects togetherCombine Account + Contacts into a single row in a table
Add UI-only fieldsAdd a checkbox, counter, or toggle that doesn't exist on the Salesforce object
Pass complex data to the frontendSend structured data from an Apex controller to Visualforce, LWC, or Aura
Perform and store calculationsStore a computed Discount or Final Amount alongside the source record
Group related recordsGroup an Opportunity with its line items for display or processing

🧱 Basic Structure of a Wrapper Class

A wrapper class is just a plain Apex class with public variables — one for each piece of data you want to bundle together. It typically includes a constructor to set default values.

Apex
public class AccountWrapper {

    public Account acc { get; set; }
    public Boolean isSelected { get; set; }

    public AccountWrapper(Account acc) {
        this.acc = acc;
        this.isSelected = false;
    }

}

Here, acc holds the Account record data, and isSelected is a UI-only checkbox field that does not exist on the Account object. The constructor initializes isSelected to false by default every time a new wrapper is created.

🛠 Example 1: Account List with Selection Checkbox

A common use case is rendering a list of records in a table where users can select individual rows using a checkbox. Since the Account object has no checkbox field, we add one via a wrapper.

Wrapper Class

Apex
public class AccountWrapper {

    public Account accountRecord { get; set; }
    public Boolean isSelected { get; set; }

    public AccountWrapper(Account acc) {
        accountRecord = acc;
        isSelected = false;
    }

}

Apex Controller

Apex
public class AccountController {

    public List<AccountWrapper> accountWrapList { get; set; }

    public AccountController() {
        accountWrapList = new List<AccountWrapper>();

        for (Account acc : [SELECT Id, Name FROM Account LIMIT 5]) {
            accountWrapList.add(new AccountWrapper(acc));
        }
    }

}

The controller queries Account records, converts each one into a wrapper object, and stores them in a list. The UI receives a list of wrappers — each containing an Account record and a ready-to-use checkbox state.

🛠 Example 2: Account with Related Contacts

Another common scenario is displaying a parent record alongside its children — for example, showing an Account with all of its Contacts in a single table row. A wrapper makes this straightforward by holding both in one object.

Wrapper Class

Apex
public class AccountContactWrapper {

    public Account acc { get; set; }
    public List<Contact> contactList { get; set; }

}

Data Assignment in Controller

Apex
List<AccountContactWrapper> wrapperList = new List<AccountContactWrapper>();

for (Account a : [SELECT Id, Name, (SELECT Id, Name FROM Contacts) FROM Account]) {

    AccountContactWrapper wrap = new AccountContactWrapper();
    wrap.acc = a;
    wrap.contactList = a.Contacts;

    wrapperList.add(wrap);

}

Each wrapper in the list now contains one Account and all of its related Contacts. The UI can iterate over wrapperList and render both in the same section — without any additional queries.

🛠 Example 3: Opportunity with Calculated Fields

Wrapper classes are also useful when you need to display values derived from calculations — fields that don't exist in Salesforce but are computed at runtime, such as a discount percentage or a final amount after applying a discount.

Wrapper Class

Apex
public class OpportunityWrapper {

    public Opportunity opp { get; set; }
    public Decimal discount { get; set; }
    public Decimal finalAmount { get; set; }

    public OpportunityWrapper(Opportunity opp, Decimal discountPercent) {
        this.opp = opp;
        this.discount = discountPercent;
        this.finalAmount = opp.Amount - (opp.Amount * discountPercent / 100);
    }

}

The wrapper holds the Opportunity record, the discount rate, and the computed final amount — all in one object. Neither discount nor finalAmount exists on the Opportunity object in Salesforce, but the wrapper makes them available to the UI seamlessly.

✅ Advantages of Wrapper Classes

AdvantageDescription
Combine Multiple ObjectsBundle Account, Contact, Opportunity, or any objects into a single structure
Add Custom FieldsInclude checkboxes, counters, calculated values, or any UI-specific property
Better UI HandlingWorks seamlessly with Visualforce tables, LWC @wire, and Aura component attributes
Cleaner CodeSeparates data structure from business logic — easier to read and maintain
ReusableDefine once, reuse across multiple controllers or components

🕐 When Should You Use a Wrapper Class?

Use a wrapper class when: multiple Salesforce objects need to be displayed or processed together, the UI requires fields that don't exist on any standard or custom object, records need to be grouped with computed or temporary values, or complex data structures need to be passed cleanly from an Apex controller to a frontend component.

You likely don't need a wrapper if you're working with a single object, all required fields already exist on that object, and no UI-specific state (like selection or calculations) is needed.

🏁 Final Thoughts

Wrapper Classes are one of those Apex patterns that seem simple on the surface but unlock a lot of flexibility in practice. By acting as a custom container for mixed or enriched data, they keep your controller logic clean, your UI code simple, and your data structures expressive. Whether you're building a selectable record table, a parent-child display, or a calculated summary view, wrapper classes are the right tool for the job. Master this pattern early — it appears constantly in real-world Salesforce development.

Welcome Back

OR
Don't have an account? Sign up