Developers · Pattern
Connect Salesforce to Salesforce using JWT
How to design an editable Salesforce table that is driven by Apex metadata instead of hardcoded columns.
When a Salesforce table starts as a simple screen, hardcoding columns feels natural. But as soon as the same component needs to support different record types, picklists, editable fields and business-specific layouts, the HTML becomes fragile.
The pattern I prefer is to split the problem into two payloads: data and metadata. Records tell the component what values exist. Metadata tells it how each value should be rendered.
The problem
A table that renders Transaction__c records may need to show dates, currency values, lookup references, record type selectors and dependent picklists. If every field is represented by custom markup, every business change becomes a code change.
Suggested payload shape
{
records: [
{ Id: 'a01...', Amount__c: 1200, Motivo__c: 'REVIEW' }
],
fields: [
{
apiName: 'Motivo__c',
label: 'Motivo',
dataType: 'Picklist',
editable: true,
picklistName: 'Motivo__c'
}
],
picklistsByRecordType: {
'012...': {
'Motivo__c': [
{ label: 'Review', value: 'REVIEW' }
]
}
}
}
Apex responsibilities
- Query the records that the screen needs.
- Describe the object and relevant fields.
- Return field labels, API names, data types and editability flags.
- Resolve picklist values by record type when the UI cannot safely infer them.
LWC responsibilities
- Iterate over
fieldsto create the table header. - For each row, use the current field metadata to decide which cell renderer to use.
- Keep draft values separate from original record values.
- Use the record type ID to select the correct picklist options.
getCellContext(row, field) {
return {
value: row[field.apiName],
isPicklist: field.dataType === 'Picklist',
isDate: field.dataType === 'Date' || field.dataType === 'DateTime',
options: this.getPicklistOptions(row.RecordTypeId, field.apiName)
};
}
Trade-offs
This design adds upfront structure. It is not worth it for a tiny one-off table. It becomes valuable when the UI must survive layout changes, multiple record types, evolving picklists or reuse across objects.
When I would use this
- Operational screens with many fields and frequent business changes.
- Components that must support more than one record type.
- Internal tools where admins request new columns often.
When I would not use this
- Very small forms with two or three stable fields.
- Highly custom interactions where every cell has unique behavior.