lwc-custom-datatable-types

Use when you need to extend `lightning-datatable` with custom cell renderings: status pills, progress bars, image thumbnails, action cells, editable pickliststo, rich-text, or any column that `lightning-datatable` does not ship out of the box. Triggers: 'custom cell type lightning datatable', 'progress bar column', 'image column', 'inline edit picklist in datatable', 'rich text column'. NOT for basic datatable usage (see `lwc-data-table`) and NOT for tree-grid or large-dataset virtualization (see `virtualized-lists`).

Best use case

lwc-custom-datatable-types is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Use when you need to extend `lightning-datatable` with custom cell renderings: status pills, progress bars, image thumbnails, action cells, editable pickliststo, rich-text, or any column that `lightning-datatable` does not ship out of the box. Triggers: 'custom cell type lightning datatable', 'progress bar column', 'image column', 'inline edit picklist in datatable', 'rich text column'. NOT for basic datatable usage (see `lwc-data-table`) and NOT for tree-grid or large-dataset virtualization (see `virtualized-lists`).

Teams using lwc-custom-datatable-types should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/lwc-custom-datatable-types/SKILL.md --create-dirs "https://raw.githubusercontent.com/PranavNagrecha/AwesomeSalesforceSkills/main/skills/lwc/lwc-custom-datatable-types/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/lwc-custom-datatable-types/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How lwc-custom-datatable-types Compares

Feature / Agentlwc-custom-datatable-typesStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Use when you need to extend `lightning-datatable` with custom cell renderings: status pills, progress bars, image thumbnails, action cells, editable pickliststo, rich-text, or any column that `lightning-datatable` does not ship out of the box. Triggers: 'custom cell type lightning datatable', 'progress bar column', 'image column', 'inline edit picklist in datatable', 'rich text column'. NOT for basic datatable usage (see `lwc-data-table`) and NOT for tree-grid or large-dataset virtualization (see `virtualized-lists`).

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# LWC Custom Datatable Types

Use this skill when `lightning-datatable` is the right shell for your grid but the built-in cell types (`text`, `number`, `url`, `email`, `button`, `boolean`, `date`, `currency`, `percent`, `phone`) cannot render or edit the column the way the feature demands. This skill covers subclassing the base datatable, registering `customTypes`, writing display and edit templates, integrating with sorting and inline edit, and avoiding the traps that silently break the extension.

---

## Before Starting

Gather this context before cutting code:

- Is the cell purely presentational (pill, bar, icon), or must it be inline-editable through the datatable's draft-values flow?
- What primitive value represents the cell for sorting purposes? Sorting compares the column's `value`, not the rendered DOM.
- How many rows will render at once? `lightning-datatable` virtualizes rows internally, but an expensive custom template multiplies that cost every scroll.
- Is the column safe to render (no raw HTML) or does it need sanitization before display?
- Will this extension be packaged? `customTypes` are defined per-subclass, so two downstream skills that each need a different custom type cannot be combined without building a merged subclass.

---

## Core Concepts

Custom cell types in `lightning-datatable` are a subclassing mechanism, not a slot API. The subclass registers types by name and points each one at a template `.html` file that sits next to the component. The base datatable then uses those templates when a column's `type` matches a registered custom type.

### Subclass `LightningDatatable` And Declare `customTypes`

The extension pattern is fixed by the platform: import the base class, extend it, and declare a static `customTypes` object whose keys are the new type names.

```javascript
import LightningDatatable from 'lightning/datatable';
import customPill from './customPill.html';
import customPillEdit from './customPillEdit.html';

export default class CustomDatatable extends LightningDatatable {
    static customTypes = {
        statusPill: {
            template: customPill,
            editTemplate: customPillEdit,        // optional — only if inline-editable
            standardCellLayout: true,            // reuse built-in padding, focus, edit icon
            typeAttributes: ['variant', 'label'] // MUST list every key you want to read
        }
    };
}
```

The `typeAttributes` array is the most important and the most missed piece. It names the keys the template is allowed to read out of the column's `typeAttributes` binding. If a key is not in that array, the datatable silently strips it, the template sees `undefined`, and nothing visibly fails — the cell just renders blank or default.

### Templates Are Data-Bound, Not Component Instances

The `template` and `editTemplate` HTML files are ordinary LWC template fragments, but they are evaluated against a fixed binding surface — `{value, typeAttributes, editable, context, keyField}` and the edit-template's editing equivalents. They have no `this`, no lifecycle hooks, no imperative handlers. A template cannot call `connectedCallback`, dispatch events from JavaScript, or hold state. If the cell needs interactive state (a multi-step toggle, debounced search, rich validation), the template must render a child LWC and delegate.

### Edit Templates Must Wire To `value` For Draft-Values

`lightning-datatable` emits `draft-values` when an inline edit is saved, and it discovers the new cell value by reading the input element's `value` property inside the edit template. An `editTemplate` that uses, for example, `lightning-combobox` must bind `value={typeAttributes.options}` for choices and set `value={value}` for the current cell value so the datatable's harness can capture the draft. Miss this wiring and the cell appears editable, but the Save button never lights up.

### Sorting Uses `value`, Not Rendered Output

The base datatable sorts by the column's primitive `value`, not by what the template paints. A status pill rendered from `{color: 'red', label: 'Hot'}` needs either a flat scalar in `value` or an explicit `sortBy` on the column so sort order matches the displayed order. Filtering through `lightning-datatable` itself does not ship — filtering is the consumer's job — but the same principle applies: whatever you filter against should be a stable scalar on the row.

### Custom Templates Compete For The Virtualization Budget

`lightning-datatable` virtualizes rows so that only visible rows are in the DOM. That budget is small. A lightweight template (a span with an SLDS class) is cheap; a `lightning-record-edit-form` or a nested datatable inside a cell multiplies per-row cost and breaks smooth scrolling at a few hundred rows. For any cell beyond a few SLDS-decorated elements, extract it into a child LWC and keep the template itself trivial.

---

## Common Patterns

### Status Pill / Badge Column

**When to use:** A column displays a categorical state (open/closed, healthy/warning/error) and needs color coding.

**How it works:** Register a `statusPill` custom type whose template renders `<span class={pillClass}>{typeAttributes.label}</span>`, driving `pillClass` from `typeAttributes.variant`. Keep the primitive `value` on the column as the sortable string so the built-in sort behaves sensibly.

**Why not the alternative:** Using `type: 'text'` and dumping a status word into the cell loses the visual affordance; wrapping every row in a child LWC that ingests the full record is heavier than the SLDS badge markup needs.

### Progress Bar Column

**When to use:** A numeric cell benefits from a bar (percent complete, score, SLA remaining).

**How it works:** Register a `progress` custom type whose template renders `<lightning-progress-bar value={value} variant={typeAttributes.variant}>`. Keep `value` as the numeric percent so sorting works without extra config.

**Why not the alternative:** Writing the percent as text hides scale; computing the bar width by hand in the template without `lightning-progress-bar` skips the accessibility attributes that SLDS ships.

### Editable Picklist Column

**When to use:** A column needs a dropdown edit without opening a row-level modal.

**How it works:** Register `editPicklist` with both `template` (read-only text span) and `editTemplate` (`lightning-combobox` whose `options` come from `typeAttributes.options` and whose `value` is bound to `value`). The datatable harness picks up the draft on blur or change and emits `draft-values`; the consumer saves them.

**Why not the alternative:** Navigating to a separate edit screen for a single-field change is slow and breaks the datatable's bulk-edit story.

### Action Cell With Multiple Buttons

**When to use:** Each row needs more than one action and the built-in `type: 'action'` menu is too limiting.

**How it works:** Register an `actionRow` type with a template that renders a horizontal stack of `lightning-button` elements. Dispatch a row event via a small child LWC if state (e.g., loading spinner) matters.

**Why not the alternative:** Embedding a full `lightning-button-group` with dynamic children inline in the template is fine; embedding a full form is not — that pattern belongs in a row-detail sub-LWC.

---

## Decision Guidance

| Situation | Recommended Approach | Reason |
|---|---|---|
| Categorical status badge or pill | Custom type with SLDS badge classes, driven by `typeAttributes.variant` | Cheap template, preserves virtualization budget |
| Numeric progress indicator | Custom type wrapping `lightning-progress-bar` | Accessible and consistent with platform UI |
| Per-row action buttons | `customTypes` with an actions array surfaced through `typeAttributes` | Keeps action logic row-scoped and event-driven |
| Full row-level edit form | Extract to a sub-LWC detail view, not a custom cell | A cell that hosts a form kills the virtualization budget |
| Editable picklist with known options | `editTemplate` using `lightning-combobox` wired to `value` | Integrates with built-in `draft-values` save flow |
| Column needs to sort on a computed key | Keep `value` as the comparable scalar; put display data in `typeAttributes` | Datatable sorts on `value`, not rendered DOM |

---

## Recommended Workflow

1. Confirm the column cannot be expressed as a built-in datatable type (re-read the base `lightning-datatable` type list).
2. Design the row shape: what scalar goes on `value`, what goes on `typeAttributes`, and whether the column is editable.
3. Scaffold the subclass: `extends LightningDatatable`, declare `static customTypes`, import each template, and list every key in `typeAttributes`.
4. Build the display template first, verify rendering on a small dataset, then add the `editTemplate` and wire `value` so `draft-values` flows correctly.
5. Profile with 200 and 1,000 rows; if scrolling lags, move interactive content into a child LWC and keep the template trivial.
6. Add sort and filter behavior by keeping `value` comparable and documenting any `sortBy` override.
7. Run `scripts/check_lwc_custom_datatable_types.py` against the component source to catch missing `typeAttributes` arrays and orphaned template filenames.

---

## Review Checklist

- [ ] The component `extends LightningDatatable` and declares `static customTypes`.
- [ ] Every registered custom type has a `typeAttributes` array listing every key its template reads.
- [ ] Each `template` and `editTemplate` points to a real sibling `.html` file next to the `.js`.
- [ ] The `editTemplate` binds the editable control's `value` to `value` so draft-values fire.
- [ ] The column's `value` is a stable scalar suitable for sorting and filtering.
- [ ] No template contains a `<lightning-record-edit-form>`, nested datatable, or heavy child tree.
- [ ] Scrolling on a representative dataset does not drop frames in a production-like org.

---

## Salesforce-Specific Gotchas

1. **`typeAttributes` names not listed are silently dropped** — a typo in the array or forgetting the array entirely makes the binding `undefined` with no console warning.
2. **Templates have no `this` and no lifecycle** — imperative handlers, `renderedCallback`, and `LightningElement` lifecycle APIs do not exist in the binding surface.
3. **Sorting ignores rendered DOM** — the column's primitive `value` drives sort order, so two rows with different pills but the same `value` appear equal.
4. **`draft-values` requires the `value` binding on the edit control** — using `selected-value` on a combobox or writing to a local proxy breaks the save path.
5. **Custom types are per-subclass** — two separate extensions cannot be mixed in one datatable instance; you must build a merged subclass that registers both.
6. **Overriding base datatable CSS is brittle** — prefer SLDS Styling Hooks where available; direct `.slds-table` overrides can break on minor-release DOM changes.
7. **Managed-package compatibility** — a subclass declared in a managed namespace renders fine, but consumers cannot add new custom types on top without a new subclass in their own namespace.

---

## Output Artifacts

| Artifact | Description |
|---|---|
| Custom datatable subclass (.js + .js-meta.xml) | The `extends LightningDatatable` component with `static customTypes` and template imports |
| Display / edit template `.html` files | One per custom type for render; one more per editable type for inline edit |
| Column configuration guidance | Sample column array showing `type`, `typeAttributes`, and `editable` wiring for the host component |
| Checker output | Findings from `check_lwc_custom_datatable_types.py`: missing `typeAttributes`, orphaned templates, non-subclass usage |

---

## Related Skills

- `lwc/lwc-data-table` — use when the column set fits the built-in types and you do not need a subclass.
- `lwc/virtualized-lists` — use when the dataset is large enough that even a well-behaved datatable is the wrong tool.
- `lwc/lwc-forms-and-validation` — use when the edit story is form-shaped rather than cell-shaped (per-row modal or record-edit-form).

Related Skills

customer-data-request-workflow

8
from PranavNagrecha/AwesomeSalesforceSkills

Implement GDPR/CCPA data subject rights (access, deletion, rectification) using Salesforce Privacy Center and/or custom workflow. NOT for general backup or org-level data retention policy.

omnistudio-custom-lwc-elements

8
from PranavNagrecha/AwesomeSalesforceSkills

Creating and integrating custom Lightning Web Components within OmniScripts: LWC override patterns, pubsub event handling, custom validation, OmniStudio data passing conventions. Use when a standard OmniScript element cannot meet a UX requirement. NOT for standalone LWC development (use lwc/* skills). NOT for Integration Procedures (use integration-procedures). NOT for embedding an OmniScript inside an LWC (use omnistudio-lwc-integration).

lwc-datatable-advanced

8
from PranavNagrecha/AwesomeSalesforceSkills

Advanced lightning-datatable patterns — inline edit + draftValues, custom cell types via extending LightningDatatable, sortable columns, infinite scroll with onloadmore, row-level errors, and the cost of large data sets. NOT for read-only display of small lists (plain lightning-datatable suffices) or fully custom grids (use a third-party library).

lwc-custom-lookup

8
from PranavNagrecha/AwesomeSalesforceSkills

Custom lookup component in LWC — typeahead/autocomplete that searches records via Apex SOSL/SOQL, shows pills, supports keyboard navigation, and manages open/close state. Use when lightning-input-field or lightning-record-picker won't work (cross-org search, computed filters, custom result rendering). NOT for in-form lookups inside lightning-record-edit-form (use lightning-input-field) or lookup filters (use admin lookup filter config).

lwc-custom-event-patterns

8
from PranavNagrecha/AwesomeSalesforceSkills

When and how to design CustomEvent traffic out of an LWC — bubbles / composed / cancelable flag choices, detail payload shape, naming rules, and propagation control. Trigger keywords: 'event not reaching parent', 'composed shadow DOM', 'CustomEvent detail mutation', 'stopPropagation vs stopImmediatePropagation'. NOT for parent-to-child communication (use `@api` — see `lwc/component-communication`), NOT for sibling fan-out (use Lightning Message Service — see `lwc/lightning-message-service`), NOT for wire-service data plumbing.

experience-cloud-search-customization

8
from PranavNagrecha/AwesomeSalesforceSkills

Use this skill when configuring or extending search on an Experience Cloud site — covering Search Manager scope configuration, LWR vs Aura search component selection, federated search setup, guest user search access, and custom search result components. NOT for SOSL/SOQL query development. NOT for internal Salesforce global search or Einstein Search for agents.

custom-property-editor-for-flow

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when building or reviewing an LWC Custom Property Editor for Flow screen or action configuration, including the `configurationEditor` metadata hook, builder-side APIs, validation, and value-change events. Triggers: 'custom property editor', 'Flow configuration editor', 'builderContext', 'inputVariables', 'configurationEditor'. NOT for ordinary runtime screen-component behavior when no Flow Builder design-time customization is involved.

flow-custom-property-editors

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when designing or reviewing Flow custom property editor patterns for screen components or actions, including when Flow Builder needs guided design-time configuration, generic type mapping, or builder-context-aware validation. Triggers: 'Flow custom property editor', 'configurationEditor', 'builderContext', 'inputVariables', 'Flow screen component setup'. NOT for general LWC runtime behavior when Flow Builder customization is not involved.

flow-apex-defined-types

8
from PranavNagrecha/AwesomeSalesforceSkills

Design and use Apex-Defined Types as Flow variables for structured non-sObject data (HTTP callout payloads, External Service responses, complex configuration). Trigger keywords: apex-defined type, flow variable, @AuraEnabled class, flow http callout response. Does NOT cover building HTTP Callout Actions themselves, External Services schema, or raw Apex invocable methods.

feature-flag-custom-metadata

8
from PranavNagrecha/AwesomeSalesforceSkills

Implement environment-safe feature flags using Custom Metadata Types for Apex, LWC, and Flow. NOT for user-level entitlements or permission sets.

custom-index-requests

8
from PranavNagrecha/AwesomeSalesforceSkills

Use when standard Salesforce indexes are insufficient for query performance on high-volume objects: requesting custom indexes via Salesforce Support for standard fields, deploying custom field indexes via Metadata API, requesting skinny tables, or designing two-column composite indexes. NOT for SOQL query optimization techniques (use data/soql-query-optimization) or general large data volume design (use architect skills).

customer-effort-scoring

8
from PranavNagrecha/AwesomeSalesforceSkills

Designing a customer experience measurement strategy using CSAT, NPS, and CES metrics in Salesforce Feedback Management: metric selection, survey timing, Feedback Management license requirements, Flow-triggered survey delivery, and CX KPI integration into Service Analytics dashboards. Use when choosing which CX metric to deploy, defining survey timing rules, or connecting survey response data to operational KPIs. NOT for building or configuring the technical survey objects, flows, or email templates (use admin/salesforce-surveys for that). NOT for custom programmatic survey delivery via API.