SharePoint column formatting

SharePoint person column formatting: avatars and people cards

Turn a person column into a compact card — initial, name, and a click-to-email link — or give a plain text name a consistent colored avatar.

A Person or Group column in SharePoint or Microsoft Lists shows a name and, in most views, a small profile photo. That's fine until you want more: the email one click away, a bigger and clearer avatar, or a name from a plain text column (an external contact, an imported spreadsheet) that has no profile at all. Column formatting JSON handles all of these.

The key thing to know is that a person column isn't text — it's an object with several properties: title (the display name), email, id, picture, sip, department, and jobTitle. Your JSON reaches into it with a dot, like [$AssignedTo.title]. Reference the column with no property and you won't get the name you expect.

Before and after

TaskAssigned to
Q1 launch planKKalya Tuckerkaylat@contoso.com
Onboarding flowMMarco Reyesmarcor@contoso.com
API migrationPPriya Nairpriyan@contoso.com
Initial from the name · name in bold · email is a mailto link
Build this person card → Opens the generator on the Person Card template. Enter your field name, copy the JSON, done.

What the SharePoint person card JSON looks like

The generator produces JSON like the example below: a circle with the first letter of the name, then a two-line block with the name and a mailto link built from the email property:

{
  "$schema": "https://developer.microsoft.com/json-schemas/sp/v2/column-formatting.schema.json",
  "elmType": "div",
  "inlineEditField": "[$AssignedTo]",
  "style": { "display": "flex", "align-items": "center", "cursor": "pointer" },
  "children": [
    {
      "elmType": "div",
      "style": {
        "width": "28px",
        "height": "28px",
        "border-radius": "50%",
        "background-color": "=if([$AssignedTo.title] == '', '#c8c6c4', '#0078d4')",
        "color": "=if([$AssignedTo.title] == '', '#323130', '#ffffff')",
        "display": "flex",
        "align-items": "center",
        "justify-content": "center",
        "font-size": "11px",
        "font-weight": "700",
        "margin-right": "8px"
      },
      "txtContent": "=if([$AssignedTo.title] == '', '–', substring([$AssignedTo.title], 0, 1))"
    },
    {
      "elmType": "div",
      "style": { "display": "flex", "flex-direction": "column", "line-height": "1.2" },
      "children": [
        {
          "elmType": "span",
          "txtContent": "=if([$AssignedTo.title] == '', 'Unassigned', [$AssignedTo.title])",
          "style": { "font-weight": "600", "font-size": "12px" }
        },
        {
          "elmType": "a",
          "attributes": {
            "href": "=if([$AssignedTo.email] == '', '', 'mailto:' + [$AssignedTo.email])",
            "target": "_blank"
          },
          "txtContent": "[$AssignedTo.email]",
          "style": { "font-size": "10px", "color": "#605e5c", "text-decoration": "none", "display": "=if([$AssignedTo.email] == '', 'none', 'inline')" }
        }
      ]
    }
  ]
}

Every reference to the person goes through a property. substring([$AssignedTo.title], 0, 1) takes the initial, [$AssignedTo.title] is the name, and the link's href is the string mailto: joined to [$AssignedTo.email]. One caveat from Microsoft's own documentation: title is the display name by default, but if the column's "Show field" setting was changed to, say, Department, then title returns the department instead.

The object also carries a picture property — the URL of the profile photo — which an img element could show. The template uses a colored initial on purpose: it needs no extra request, never shows a broken-image icon, and looks identical for guests and external users who have no photo.

Names in a text column

If your names live in a single line of text column — a vendor contact, a name typed by hand, an import — there's no person object to read from. The Initials Avatar template works on plain text: it takes the first letter, picks a color from that letter so the same person is always the same color, and shows Unassigned with a grey circle when the cell is empty.

How to apply it

  1. Open the generator and pick the Person Card template (or Initials Avatar for a text column).
  2. Enter your column's internal field name — see the note below.
  3. Click Copy.
  4. In SharePoint: Column settings → Format this column → Advanced mode.
  5. Delete what's in the box, paste, click Preview, then Save.
Most common reason it doesn't work: the field name must match your column's internal name, which can differ from the display name. The built-in "Assigned To" column, for instance, is AssignedTo internally. See the internal field name guide to find yours.

Common questions

Which properties of a person column can I use?
A person column is an object with title, email, id, picture, sip, department, and jobTitle. Reference one with a dot — [$AssignedTo.title] for the display name, [$AssignedTo.email] for the address. Using the bare column without a property does not give you the name.
Does it work for a column that allows multiple people?
Not as generated. A multi-select person column holds an array, so [$AssignedTo.title] only resolves for a single value. Showing several people needs a forEach loop in the JSON, which the Person Card template does not include — treat it as a starting point and add forEach by hand.
Can I show the real profile photo instead of an initial?
The person object includes a picture property with the profile photo URL, so an img element can display it. The template uses a colored initial instead because it renders instantly, needs no image request, and looks the same for guests who have no photo.
My names are in a plain text column, not a person column — can I still get avatars?
Yes — use the Initials Avatar template. It takes the first letter of the text and derives a color from it, so each name gets the same color every time, and it shows Unassigned when the cell is empty.