SharePoint column formatting

SharePoint conditional formatting: show a value only when another column matches

Keep a column quiet until it matters — the blocker note only when Status is Blocked, the reason only when a request is rejected — with one expression on the display property.

Some columns are only relevant in one situation. A Blocker notes column matters when the item is blocked and is clutter the rest of the time; a Rejection reason only means something once someone has said no. SharePoint and Microsoft Lists can't hide a column per row, but column formatting JSON can read another column in the same row and decide whether to draw anything at all.

The mechanism is a single style property: display. Set it to none when the condition fails and to a normal value when it passes, and the cell is empty or filled accordingly. The column header stays — this is a display rule, not a permission — but the row-level noise is gone.

Before and after

ItemStatusBlocker notes
API migrationBlockedWaiting on vendor
Q1 launch planIn Progress
Brand refreshBlockedLegal review
Onboarding flowDone
Notes are shown only when Status is Blocked — the other rows keep their value but draw nothing
Build this conditional formatter → Opens the generator on the Conditional Visibility template. Enter the field to show, the field to test, and the value; copy the JSON; done.

What the SharePoint conditional visibility JSON looks like

The generator produces JSON like the example below. It formats the Notes column, but the test inside it reads Status:

{
  "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json",
  "elmType": "div",
  "inlineEditField": "[$Notes]",
  "txtContent": "[$Notes]",
  "style": {
    "padding": "3px 8px",
    "border-radius": "3px",
    "background-color": "#fff4ce",
    "color": "#323130",
    "font-size": "12px",
    "cursor": "pointer",
    "display": {
      "operator": "?",
      "operands": [
        { "operator": "==", "operands": ["[$Status]", "Blocked"] },
        "inline-block",
        "none"
      ]
    }
  }
}

Everything except the last line is ordinary styling — a soft yellow note chip. The display expression is the switch: when [$Status] equals Blocked the chip renders as inline-block, otherwise it's none and the cell is blank. It's written in SharePoint's object form (? with three operands) rather than =if(…) because the string syntax can't escape a quote — a condition value like Client's review would never match — while an object operand is a plain JSON string. Both forms mean the same thing, and the =if(…) spelling in the questions below is fine to hand-edit when your values have no apostrophes. The formatter is applied to the Notes column, so inlineEditField still lets people click and edit the note when it's visible.

One rule governs every cross-column reference, and it's the cause of nearly every "it never shows" report: the column you read must be in the same view. Microsoft's documentation states it plainly — references to other fields work only if they're included in the view. If Status is hidden from the view, [$Status] has no value, the comparison fails, and the note stays hidden on every row. Add the column to the view; you can make it narrow, but it has to be there.

Conditions can be as rich as you need. && and || combine tests; @me is the current user's email, so [$Owner.email] == @me shows a value only to the item's owner — Microsoft's own examples use exactly that pattern for a per-user hide. And you don't have to hide: put the same if() on txtContent instead and show a dash, a hint, or a different field when the condition isn't met.

How to apply it

  1. Open the generator and pick the Conditional Visibility template (or use the button above).
  2. Enter the internal name of the field to show, the condition field to test, and the condition value it must equal.
  3. Click Copy.
  4. In SharePoint, open the settings of the column you want to show or hide (not the condition column): Column settings → Format this column → Advanced mode.
  5. Delete what's in the box, paste, click Preview, then Save.
  6. Make sure the condition column is in the view, or nothing will ever show.
Most common reason it doesn't work: both field names must be the columns' internal names, which can differ from the display names — and this template has two of them. See the internal field name guide to find yours.

Common questions

Can I hide the entire column, header included?
No. Column formatting only controls the cell's contents, so the header and the empty cell stay. To remove a column completely for some people, use a separate view — formatting is a display tweak, not security, and the value is still in the page.
Why does the value never appear, even when the condition is true?
Almost always because the condition column is not in the view. A formatter can only read other columns that are included in the same view, so add the Status column (or whatever you compare against) to the view. Check the value's spelling and capitalization too — Blocked and blocked are different.
Can I combine two conditions?
Yes. The expression language supports && for and, || for or, so display can be =if([$Status] == 'Blocked' && [$Owner.email] == @me, 'inline-block', 'none'). Edit the display line in the JSON the generator gives you.
Can I show something for everyone else instead of nothing?
Yes. Instead of switching display, put the condition on txtContent: =if([$Status] == 'Blocked', [$Notes], '—') shows the note when blocked and a dash otherwise. The generator's status templates use the same pattern for empty values.