- Published on
SPFx Web Part vs Application Customizer vs Field Customizer
One of the most common questions from developers new to the SharePoint Framework is: "I need to customise this page β which SPFx type do I use?"
The answer depends entirely on what you need to customise and where it needs to appear.
This guide cuts through the confusion with a clear breakdown of each extensibility model, when to reach for it, and when to rule it out.
ποΈ The Four SPFx Extensibility Types
SPFx gives you four distinct ways to extend SharePoint:
| Type | Scaffolded as | Primary DOM target |
|---|---|---|
| Web Part | --extension-type webpart | A content zone on a page |
| Application Customizer | --extension-type applicationCustomizer | Page-level header / footer placeholders |
| Field Customizer | --extension-type fieldCustomizer | A single list column cell |
| Command Set | --extension-type listViewCommandSet | List / library toolbar and context menu |
Each type has a different registration mechanism, a different rendering surface, and a different lifecycle. Picking the wrong one wastes days.
π§© Web Parts
A web part is a self-contained UI component that a page editor drops onto a modern SharePoint page from the toolbox.
Use a web part when:
- The feature is optional, page-by-page β editors choose where and whether to add it
- The component needs to occupy space within a page content area
- You want property pane configuration per instance
- The feature is standalone: a dashboard, a news feed, a form, a directory
Do not use a web part when:
- You need the same UI to appear on every page automatically (use an application customizer instead)
- You need to change how a list column renders in list view (use a field customizer)
- You need a toolbar button on a list (use a command set)
Key characteristics:
- Registered in the page via drag-and-drop by a site editor
- Each instance has its own
this.propertiesbag β isolated configuration - Deployed via App Catalog; activated per site
- React, no-framework, or any JS framework supported
- Available in SharePoint, Teams tabs, Viva Connections, and Outlook (with manifest changes)
Real examples: Employee directory, approval dashboard, document request form, weather widget, announcements roller.
πΌοΈ Application Customizer
An application customizer runs on every page within a site (or the entire tenant if deployed broadly). It renders into two named placeholders: Top and Bottom.
Use an application customizer when:
- You need a consistent UI element that appears on every page β a global nav bar, a cookie banner, a help button, a footer with links
- The feature must activate automatically without editors adding anything to a page
- You need to inject JavaScript or CSS that runs globally per page load
Do not use an application customizer when:
- The feature should be optional per-page (use a web part)
- You need to customise a list column cell (use a field customizer)
Key characteristics:
- Deployed via the App Catalog and provisioned with a
UserCustomActionon a site or tenant - Cannot render arbitrary content zones on the page β only
TopandBottomplaceholders - Runs for every user on every modern page within its scope
- One application customizer per feature definition; multiple can coexist on the same site
- SharePoint injects the placeholder
<div>β your code renders into it viaReactDOM.render
Real examples: Global navigation mega-menu, sticky header with breadcrumb, GDPR cookie banner, tenant-wide notification bar, footer with corporate links.
// Accessing the Top placeholder in an Application Customizer
const topPlaceholder = this.context.placeholderProvider.tryCreateContent(
PlaceholderName.Top,
{ onDispose: this._onDispose }
);
if (topPlaceholder) {
ReactDOM.render(React.createElement(GlobalNavBar, { context: this.context }), topPlaceholder.domElement);
}
π·οΈ Field Customizer
A field customizer replaces the default cell renderer for a specific list column. Instead of showing plain text or a date, you render any React component inside each cell.
Use a field customizer when:
- You want to show a status badge, a coloured pill, an icon, a sparkline, or a progress bar in a list column
- The column value needs to be formatted beyond what JSON column formatting can do
- Your rendering logic requires external data, complex conditionals, or interactive elements (tooltips, expand/collapse)
Do not use a field customizer when:
- JSON column formatting is sufficient β it's faster to deploy, requires no app catalog, and is editable by power users directly in the list settings. JSON formatting handles the vast majority of colour-coding, icon, and badge scenarios. Only reach for a field customizer when you genuinely need TypeScript logic or React components.
- You need something on every page (use an application customizer)
- You need a toolbar action (use a command set)
Key characteristics:
- Registered on a specific list column via
ClientSideComponentIdin the field's schema XML or via PnPjs/PowerShell provisioning - Receives
this.event.fieldValue(the raw column value) andthis.event.listItem(the full item) as context - Renders in every row of list view for that column β keep rendering fast and side-effect-free
- Each column instance is independent; multiple field customizers can run on the same list view
Real examples: Traffic-light status indicator, file size formatted as KB/MB/GB, person card with presence indicator, date displayed as relative time ("3 days ago"), clickable rating stars.
// Field Customizer render method
public renderCell(): void {
const value = this.event.fieldValue;
const element = React.createElement(StatusBadge, { status: value });
ReactDOM.render(element, this.event.domElement);
}
β‘ Command Set (List View Command Set)
A command set adds custom buttons to the command bar and right-click context menu of a list or library. It fires an action when the user selects one or more items and clicks the button.
Use a command set when:
- You need a "do something with selected items" action β bulk edit, bulk move, export, send for approval
- The action is contextual β enabled only when certain items are selected, or only for certain users
- You want a custom action in the list toolbar that is not available natively
Key characteristics:
- Registered via
ClientSideComponentIdon a list or library (or via site/tenant-scoped deployment) - Receives
this.context.listView.selectedRowsβ the currently selected list items - Can control button visibility and enabled state dynamically via
onListViewUpdated - Opens panels, dialogs, or redirects β does not render inline in the list
Real examples: "Submit for approval" button on document library, bulk-tag selected items, export selected rows to Excel, copy items between libraries.
π€ Decision Guide
Use this table as a quick reference when a new requirement lands:
| Requirement | Reach for |
|---|---|
| Drop a component onto a specific page | Web Part |
| Appears on every page automatically | Application Customizer |
| Add a global header or footer | Application Customizer |
| Change how a list column looks | Field Customizer (or JSON formatting first) |
| Add a button to the list toolbar | Command Set |
| Action on selected list items | Command Set |
| Per-page configuration by editors | Web Part |
| Works in Teams / Viva / Outlook | Web Part (with manifest changes) |
π Combining Types
Real-world solutions often combine types. A document management solution might use:
- A web part for the document request submission form on a page
- An application customizer for a persistent "My Requests" notification badge in the header
- A field customizer to show a coloured approval status in the document library
- A command set to let users bulk-submit selected documents for review
Each type handles what it is designed for. The combination covers the full experience without forcing any one type to do a job it was not built for.
β Summary
- Web part β optional, page-by-page, editor-controlled component inside a content zone.
- Application customizer β automatic, page-level, header/footer injection across all pages in a site or tenant.
- Field customizer β custom cell renderer for a specific list column; replaces the default display with any React component.
- Command set β toolbar and context menu actions on list and library items.
- When in doubt: if it goes on a page voluntarily β web part. If it must be everywhere β application customizer. If it changes a column cell β field customizer (or JSON formatting). If it acts on selected rows β command set.
Choosing the right type upfront saves you from a painful refactor halfway through the project.
Happy coding!
Author
Ravichandran@Hi_Ravichandran
