Create Dynamic Picklists for Your Custom Components

You can expose a component property as a picklist when the component is configured in the Lightning App Builder. The picklist’s values are provided by an Apex class that you create.

For example, let’s say you’re creating a component for the Home page to display a custom Company Announcement record. You can use an Apex class to put the titles of all Company Announcement records in a picklist in the component’s properties in the Lightning App Builder. Then, when admins add the component to a Home page, they can easily select the appropriate announcement to place on the page.

First, create a custom Apex class to use as a datasource for the picklist. The Apex class must extend the VisualEditor.DynamicPickList abstract class. Then add an attribute to your design file that specifies your custom Apex class as the datasource.

Here’s a simple example.

Create an Apex Class

global class MyCustomPickList extends VisualEditor.DynamicPickList{
    
    global override VisualEditor.DataRow getDefaultValue(){
        VisualEditor.DataRow defaultValue = new VisualEditor.DataRow('red', 'RED');
        return defaultValue;
    }
    global override VisualEditor.DynamicPickListRows getValues() {
        VisualEditor.DataRow value1 = new VisualEditor.DataRow('red', 'RED');
        VisualEditor.DataRow value2 = new VisualEditor.DataRow('yellow', 'YELLOW');
        VisualEditor.DynamicPickListRows  myValues = new VisualEditor.DynamicPickListRows();
        myValues.addRow(value1);
        myValues.addRow(value2);
        return myValues;
    }
}

Although VisualEditor.DataRow allows you to specify any Object as its value, you can specify a datasource only for String attributes. The default implementation for isValid() and getLabel() assumes that the object passed in the parameter is a String for comparison.

Note

For more information on the VisualEditor.DynamicPickList abstract class, see the Apex Reference Guide.

Add the Apex Class to Your Design File

To specify an Apex class as a datasource in an existing component, add the datasource property to the attribute with a value consisting of the Apex namespace and Apex class name.

<design:component>
        <design:attribute name="property1" datasource="apex://MyCustomPickList"/>
</design:component>

Dynamic Picklist Tips and Considerations

If you make an Apex datasource private using WITH USER_MODE in the object query, use the component only on pages that users with appropriate object access permission can view. Otherwise, the component can still be visible to users who lack appropriate permission, thereby exposing a private data string.

Let’s look at some scenarios. If a user doesn’t have appropriate object access permission:
  • Both Aura components and Lightning web components are still visible on Lightning pages
  • In LWR sites in Experience Cloud, Lightning web components are still visible on private pages and to guest users on public pages
  • In Aura sites in Experience Cloud, Aura components and Lightning web components aren’t visible

See Securing Data in Apex Controllers.

Important

  • You can use VisualEditor.DesignTimePageContext to give your picklist the context of the page that the component resides on.
  • Specifying the Apex datasource as public isn’t respected in managed packages. If an Apex class is public and part of a managed package, it can be used as a datasource for custom components in the subscriber org.
  • Profile access on the Apex class isn’t respected when the Apex class is used as a datasource. If an admin’s profile doesn’t have access to the Apex class but does have access to the custom component, the admin sees values provided by the Apex class on the component in the Lightning App Builder.
  • The VisualEditor.DynamicPickList method isValid() runs in Experience Cloud sites when the page loads. If you don’t override the method in your custom Apex class that extends VisualEditor.DynamicPickList, the default implementation executes getValues() at runtime, which can cause performance degradations. To improve performance, implement a non-operational isValid() method.
    global override Boolean isValid(Object attributeValue) {
       return true;
    }