Blog

SPFx Web Part vs Application Customizer vs Field Customizer

23 Nov 2024
SPFxSharePointExtensionsApplication CustomizerField CustomizerWeb Part

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:

TypeScaffolded asPrimary DOM target
Web Part--extension-type webpartA content zone on a page
Application Customizer--extension-type applicationCustomizerPage-level header / footer placeholders
Field Customizer--extension-type fieldCustomizerA single list column cell
Command Set--extension-type listViewCommandSetList / 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.properties bag β€” 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 UserCustomAction on a site or tenant
  • Cannot render arbitrary content zones on the page β€” only Top and Bottom placeholders
  • 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 via ReactDOM.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 ClientSideComponentId in the field's schema XML or via PnPjs/PowerShell provisioning
  • Receives this.event.fieldValue (the raw column value) and this.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 ClientSideComponentId on 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:

RequirementReach for
Drop a component onto a specific pageWeb Part
Appears on every page automaticallyApplication Customizer
Add a global header or footerApplication Customizer
Change how a list column looksField Customizer (or JSON formatting first)
Add a button to the list toolbarCommand Set
Action on selected list itemsCommand Set
Per-page configuration by editorsWeb Part
Works in Teams / Viva / OutlookWeb 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!