SharePoint Approval Status Badges with Column Formatting JSON

Turn the built-in moderation status into a clean icon + color “pill” (plus 3 variations you can reuse).

When you enable Content Approval on a SharePoint list or library, SharePoint exposes an internal moderation value (commonly shown as Approval Status). Out of the box, it’s not very “scan-friendly” in a busy view. With Column Formatting JSON, you can transform that value into a modern badge with:

  • A colored background (pill)
  • A status icon
  • Optional border rules
  • A tooltip for clarity

This is pure UI formatting: it doesn’t change data, permissions, or workflow behavior—only how the column is rendered in views.


Why Approval Status formatting is worth doing

In real list views, people scan status first. The difference between Pending vs Approved vs Draft should be visible instantly—without opening the item.

A status badge provides:

  • Immediate recognition (color + icon)
  • Faster triage in approvals-heavy lists
  • Consistent UX across lists if you standardize the JSON

The key detail: Approval Status numeric mapping

Your JSON uses Number(@currentField) which means the column is being treated as a numeric moderation value.

Here is the commonly used mapping for moderation status:

Numeric valueMeaning
0Approved
1Denied / Rejected
2Pending
3Draft
4Scheduled

That’s why your if(Number(@currentField)==0, ...) must be interpreted as Approved, not Draft.


How your JSON works (what each part does)

Your formatter renders this structure:

  1. Outer container (div)
    Used mostly for layout and spacing.
  2. Pill container
    • Flex row layout
    • border-radius: 20px → pill shape
    • Conditional background color using ms-bgColor-* classes
    • Optional border when Draft (==3)
  3. Icon bubble
    • A small circle (border-radius: 50%)
    • White background
    • Icon and icon color change per status
  4. Text label
    • Uses @currentField (so it might show numeric value in some views)
    • Conditional font color (white on dark backgrounds, dark on white)

Step-by-step: How to apply Column Formatting JSON

Step 1 — Confirm Content Approval is enabled

  1. Go to your list/library → Settings
  2. Open Versioning settings
  3. Enable Content Approval
  4. Save

Without content approval, the moderation status may not be meaningful.

Step 2 — Open the formatting panel

  1. Go to your view
  2. Find the Approval Status column
  3. Column menu → Column settings
  4. Click Format this column

Step 3 — Paste JSON + Preview

  1. Paste the JSON you want (base or a variation below)
  2. Use Preview and test items in multiple states
  3. Click Save

Step 4 — Validate in a real view

  • Check readability on both light and dark list themes
  • Make sure Draft doesn’t look like “Disabled”
  • Confirm the icon choices match what your users understand

BASE FORMATTER (Your JSON, ready to paste)

This is your formatter as provided. It produces a pill badge with icon + text.

{
"$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json",
"elmType": "div",
"children": [
{
"elmType": "div",
"style": {
"display": "flex",
"flex-direction": "column",
"align-items": "flex-start",
"margin": "7px 0px",
"white-space": "nowrap"
},
"children": [
{
"elmType": "div",
"style": {
"display": "flex",
"flex-direction": "row",
"align-items": "center",
"padding": "3px",
"border-radius": "20px",
"border": "=if(Number(@currentField)==3,'1px solid','')"
},
"attributes": {
"class": "=if(Number(@currentField)==0,'ms-bgColor-tealLight',if(Number(@currentField)==1,'ms-bgColor-sharedRed10',if(Number(@currentField)==2,'ms-bgColor-sharedBlueMagenta10',if(Number(@currentField)==3,'ms-bgColor-white','ms-bgColor-blue'))))"
},
"children": [
{
"elmType": "div",
"style": {
"padding": "4px",
"border-radius": "50%",
"font-weight": "bold"
},
"attributes": {
"iconName": "=if(Number(@currentField)==0,'Accept',if(Number(@currentField)==1,'Cancel',if(Number(@currentField)==2,'Forward',if(Number(@currentField)==3,'CalculatorSubtract','EventAccepted'))))",
"class": "='ms-fontSize-10 ms-bgColor-white '+if(Number(@currentField)==0,'ms-fontColor-teal',if(Number(@currentField)==1,'ms-fontColor-sharedRed10',if(Number(@currentField)==2,'ms-fontColor-sharedBlueMagenta10',if(Number(@currentField)==3,'','ms-fontColor-blue'))))"
}
},
{
"elmType": "div",
"txtContent": "@currentField",
"style": {
"margin": "0px 7px"
},
"attributes": {
"class": "=if(Number(@currentField)==3,'','ms-fontColor-white')"
}
}
]
}
]
}
]
}

Three variations you can publish and reuse

Each variation solves a practical UX need you’ll run into in real SharePoint views.


Variation 1 — Human-readable labels (instead of 0/1/2/3/4)

If your view displays the numeric value, users will see “2” instead of “Pending”. This variation generates a friendly label using the mapping.

When to use

  • Your list shows numeric status values
  • You want consistent text across all views
{
"$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json",
"elmType": "div",
"style": {
"display": "flex",
"align-items": "center",
"padding": "4px 10px",
"border-radius": "999px",
"white-space": "nowrap"
},
"attributes": {
"class": "=if(Number(@currentField)==0,'ms-bgColor-tealLight',if(Number(@currentField)==1,'ms-bgColor-sharedRed10',if(Number(@currentField)==2,'ms-bgColor-sharedBlueMagenta10',if(Number(@currentField)==3,'ms-bgColor-white',if(Number(@currentField)==4,'ms-bgColor-sharedOrange10','ms-bgColor-neutralLight')))))",
"title": "=if(Number(@currentField)==0,'Approved',if(Number(@currentField)==1,'Denied',if(Number(@currentField)==2,'Pending',if(Number(@currentField)==3,'Draft',if(Number(@currentField)==4,'Scheduled','Unknown')))))"
},
"children": [
{
"elmType": "span",
"style": { "margin-right": "8px" },
"attributes": {
"iconName": "=if(Number(@currentField)==0,'Accept',if(Number(@currentField)==1,'Cancel',if(Number(@currentField)==2,'Clock',if(Number(@currentField)==3,'Edit',if(Number(@currentField)==4,'Calendar','StatusCircleQuestionMark')))))",
"class": "='ms-fontSize-14 ms-bgColor-white ' + if(Number(@currentField)==0,'ms-fontColor-teal',if(Number(@currentField)==1,'ms-fontColor-sharedRed20',if(Number(@currentField)==2,'ms-fontColor-sharedBlueMagenta20',if(Number(@currentField)==3,'ms-fontColor-neutralPrimary',if(Number(@currentField)==4,'ms-fontColor-sharedOrange20','ms-fontColor-neutralPrimary')))))"
}
},
{
"elmType": "span",
"txtContent": "=if(Number(@currentField)==0,'Approved',if(Number(@currentField)==1,'Denied',if(Number(@currentField)==2,'Pending',if(Number(@currentField)==3,'Draft',if(Number(@currentField)==4,'Scheduled','Unknown')))))",
"attributes": {
"class": "=if(Number(@currentField)==3,'ms-fontColor-neutralPrimary','ms-fontColor-white')"
}
}
]
}

Variation 2 — Icon-only “compact mode” (best for dense lists)

Sometimes you don’t have horizontal space. This version shows only a colored circle + icon, and uses tooltip for the label.

When to use

  • You have many columns
  • You want a minimal “status indicator”
{
"$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json",
"elmType": "div",
"style": {
"display": "flex",
"align-items": "center",
"justify-content": "center",
"width": "28px",
"height": "28px",
"border-radius": "50%"
},
"attributes": {
"title": "=if(Number(@currentField)==0,'Approved',if(Number(@currentField)==1,'Denied',if(Number(@currentField)==2,'Pending',if(Number(@currentField)==3,'Draft',if(Number(@currentField)==4,'Scheduled','Unknown')))))",
"class": "=if(Number(@currentField)==0,'ms-bgColor-tealLight',if(Number(@currentField)==1,'ms-bgColor-sharedRed10',if(Number(@currentField)==2,'ms-bgColor-sharedYellow10',if(Number(@currentField)==3,'ms-bgColor-neutralLight',if(Number(@currentField)==4,'ms-bgColor-sharedOrange10','ms-bgColor-neutralLight')))))"
},
"children": [
{
"elmType": "span",
"attributes": {
"iconName": "=if(Number(@currentField)==0,'Accept',if(Number(@currentField)==1,'Cancel',if(Number(@currentField)==2,'Clock',if(Number(@currentField)==3,'Edit',if(Number(@currentField)==4,'Calendar','StatusCircleQuestionMark')))))",
"class": "=if(Number(@currentField)==3,'ms-fontColor-neutralPrimary','ms-fontColor-white')"
}
}
]
}

Variation 3 — Explicit “Scheduled” (4) + “Unknown” fallback (robust governance)

Your base JSON has a final “else” that implicitly covers “Scheduled” and unknown values. This version handles them explicitly to avoid confusion later.

When to use

  • You want long-term reliability
  • You expect more moderation states or odd values in some libraries
{
"$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json",
"elmType": "div",
"style": {
"display": "flex",
"align-items": "center",
"padding": "3px 8px",
"border-radius": "16px",
"white-space": "nowrap"
},
"attributes": {
"class": "=if(Number(@currentField)==0,'ms-bgColor-tealLight',if(Number(@currentField)==1,'ms-bgColor-sharedRed10',if(Number(@currentField)==2,'ms-bgColor-sharedBlueMagenta10',if(Number(@currentField)==3,'ms-bgColor-white',if(Number(@currentField)==4,'ms-bgColor-sharedOrange10','ms-bgColor-neutralLight')))))",
"title": "=if(Number(@currentField)==0,'Approved',if(Number(@currentField)==1,'Denied',if(Number(@currentField)==2,'Pending',if(Number(@currentField)==3,'Draft',if(Number(@currentField)==4,'Scheduled','Unknown')))))"
},
"children": [
{
"elmType": "span",
"style": {
"padding": "4px",
"border-radius": "50%",
"margin-right": "6px"
},
"attributes": {
"iconName": "=if(Number(@currentField)==0,'Accept',if(Number(@currentField)==1,'Cancel',if(Number(@currentField)==2,'Forward',if(Number(@currentField)==3,'CalculatorSubtract',if(Number(@currentField)==4,'Calendar','StatusCircleQuestionMark')))))",
"class": "='ms-fontSize-12 ms-bgColor-white ' + if(Number(@currentField)==0,'ms-fontColor-teal',if(Number(@currentField)==1,'ms-fontColor-sharedRed20',if(Number(@currentField)==2,'ms-fontColor-sharedBlueMagenta20',if(Number(@currentField)==3,'ms-fontColor-neutralPrimary',if(Number(@currentField)==4,'ms-fontColor-sharedOrange20','ms-fontColor-neutralPrimary')))))"
}
},
{
"elmType": "span",
"txtContent": "=if(Number(@currentField)==0,'Approved',if(Number(@currentField)==1,'Denied',if(Number(@currentField)==2,'Pending',if(Number(@currentField)==3,'Draft',if(Number(@currentField)==4,'Scheduled','Unknown')))))",
"attributes": {
"class": "=if(Number(@currentField)==3,'ms-fontColor-neutralPrimary','ms-fontColor-white')"
}
}
]
}

Practical recommendations (what I’d standardize)

If you want this to be a reusable “pattern” in your environment:

  • Use Variation 1 as default (readable labels, explicit mapping).
  • Use Variation 2 for “dashboard-like” list views with many columns.
  • Use Variation 3 in libraries where “Scheduled” is actively used.

Final table — Implementation steps (copy-paste checklist)

StepActionResult
1Enable Content Approval in Versioning SettingsApproval Status becomes meaningful
2Open Format this column in the Approval Status columnJSON editor opens
3Paste Base or a Variation JSONBadge UI is rendered
4Preview items in multiple statesValidate icon/color logic
5Save formattingView is updated for users

Final table — Technical cheat sheet (expressions + UX)

TopicBest practiceWhy it matters
Number(@currentField)Always assume numeric mapping 0–4Prevents wrong status interpretation
Background classesUse ms-bgColor-* classesKeeps Fluent UI look consistent
Light backgroundsSwitch text to neutral/darkWhite on white becomes unreadable
Tooltips (title)Add human-readable meaningHelps icon-only and quick scanning
Scheduled/UnknownHandle explicitly (Variation 3)Improves long-term reliability

Edvaldo Guimrães Filho Avatar

Published by