Working with SharePoint Person Fields in Power Apps

Three reliable ways to populate a single-value SharePoint Person column from SharePoint choices, a controlled project-manager list, or Office 365 Users.

A SharePoint Person column looks like a name in the list, but Power Apps treats it as a record rather than plain text.

That distinction matters whenever the control used to select a person gets its records from somewhere other than the Person column itself. Two records can refer to the same user and still be incompatible because their field names and schemas are different.

This post compares three ways to populate a single-value Project Manager Person column in a SharePoint list called Projects:

  1. Use the choices exposed by the SharePoint Person column.
  2. Restrict the selection to a predefined pool stored in a separate SharePoint list.
  3. Search the organization directory through the Office 365 Users connector.

The Person Record SharePoint Expects

A SharePoint Person value is an object. When Power Apps writes to the column, the SharePoint connector commonly expects a record shaped like this:

{
    '@odata.type': "#Microsoft.Azure.Connectors.SharePoint.SPListExpandedUser",
    Claims: "i:0#.f|membership|user@contoso.com",
    DisplayName: "Alex Wilber",
    Email: "user@contoso.com"
}

The connector can also expose properties such as Department, JobTitle, and Picture. The important point is that a text value such as "Alex Wilber" or "user@contoso.com" is not, by itself, a SharePoint Person record.

In the examples below, ddlProjectManager is a single-select Combo box inside the Project Manager data card.

In the classic Combo box, use DefaultSelectedItems. The older Default property is deprecated. For a generated SharePoint form, Parent.Default is also a good starting point when the control's Items schema matches the data card value.

Case 1: Use the SharePoint Person Column's Choices

The simplest approach is to let the SharePoint column supply the records:

Choices(
    [@Projects].'Project Manager',
    Self.SearchText
)

Set the data card's Update property to:

ddlProjectManager.Selected

Set the Combo box's DefaultSelectedItems property to:

ThisItem.'Project Manager'

This works because Items, Selected, and the existing SharePoint value all use the SharePoint Person schema.

Does Choices Bind Directly to Office 365 Users?

Not quite. Choices([@Projects].'Project Manager') asks the SharePoint connector for valid choices for that Person column. SharePoint resolves people from the directory according to the column and tenant configuration, but the app is not calling the Office 365 Users connector directly.

This distinction is useful:

  • Choices(...) returns SharePoint-shaped Person records that can normally be saved without conversion.
  • Office365Users.SearchUserV2(...) returns Microsoft Graph user records that must be converted before SharePoint can save them.

Use this first pattern when users may choose anyone SharePoint makes available to the Person column.

Case 2: Use a Predefined Project-Manager Pool

Sometimes project managers must come from a controlled list instead of the entire directory.

Suppose a separate SharePoint list called Users contains:

  • Title: the person's display name;
  • Email: the person's email address;
  • Role: either a Text or Choice column;
  • Pillar Code: a Choice column used to narrow the pool.

The Combo box can show only project managers for the selected pillar:

ShowColumns(
    Filter(
        Users,
        'Pillar Code'.Value = ddPillarCode.Selected.Value &&
        Role = "PM"
    ),
    Title,
    Email
)

If Role is a SharePoint Choice column, compare its Value instead:

Role.Value = "PM"

The selected record now contains Title and Email. It does not contain SharePoint's Claims and DisplayName fields, so assigning ddlProjectManager.Selected directly to the data card produces a schema mismatch.

Build the Person record manually in the data card's Update property:

With(
    {
        selectedEmail: Lower(ddlProjectManager.Selected.Email)
    },
    {
        '@odata.type': "#Microsoft.Azure.Connectors.SharePoint.SPListExpandedUser",
        Claims: "i:0#.f|membership|" & selectedEmail,
        DisplayName: ddlProjectManager.Selected.Title,
        Email: selectedEmail
    }
)

The Combo box's existing value must match its Items schema, not the SharePoint Person schema. Set DefaultSelectedItems to:

{
    Title: ThisItem.'Project Manager'.DisplayName,
    Email: ThisItem.'Project Manager'.Email
}

An even safer edit-form default is to retrieve the matching row from the same data source:

LookUp(
    ShowColumns(
        Filter(
            Users,
            'Pillar Code'.Value = ddPillarCode.Selected.Value &&
            Role = "PM"
        ),
        Title,
        Email
    ),
    Lower(Email) = Lower(ThisItem.'Project Manager'.Email)
)

This version guarantees that the default record comes from the same table expression as Items.

Case 3: Search Office 365 Users Directly

Add the Office 365 Users connector to the canvas app before using this approach.

Set the Combo box's Items property to:

Office365Users.SearchUserV2(
    {
        searchTerm: ddlProjectManager.SearchText,
        top: 10
    }
).value

SearchUserV2 returns directory fields such as:

  • DisplayName
  • Mail
  • UserPrincipalName
  • JobTitle
  • Department

Notice that this schema uses DisplayName and Mail. It does not use Title for the person's name, and JobTitle is the job-title field.

Convert the selected directory user into a SharePoint Person record in the data card's Update property:

With(
    {
        selectedEmail: Lower(
            Coalesce(
                ddlProjectManager.Selected.Mail,
                ddlProjectManager.Selected.UserPrincipalName
            )
        )
    },
    {
        '@odata.type': "#Microsoft.Azure.Connectors.SharePoint.SPListExpandedUser",
        Claims: "i:0#.f|membership|" & selectedEmail,
        DisplayName: ddlProjectManager.Selected.DisplayName,
        Email: selectedEmail
    }
)

Coalesce handles accounts whose Mail property is blank by falling back to UserPrincipalName.

Default Value for an Existing Project

The SharePoint record contains Email; it does not contain an Office 365 Users Mail property. Therefore, this expression is not valid:

ThisItem.'Project Manager'.Mail

The most reliable default is to search for the existing SharePoint email and return the matching Office 365 Users record. That keeps the default in exactly the same schema as Items:

LookUp(
    Office365Users.SearchUserV2(
        {
            searchTerm: ThisItem.'Project Manager'.Email,
            top: 10
        }
    ).value,
    Lower(
        Coalesce(
            Mail,
            UserPrincipalName
        )
    ) = Lower(ThisItem.'Project Manager'.Email)
)

Set this formula on DefaultSelectedItems.

This requires another directory query when the form loads. If that cost matters, load or cache the matching directory user when the form opens.

Why Items and DefaultSelectedItems Must Agree

The Combo box is concerned with the schema of the records it displays:

Items schema = DefaultSelectedItems schema

The SharePoint data card is concerned with the schema written back to its column:

Update schema = SharePoint Person schema

These are separate boundaries.

For example, the controlled Users list gives the Combo box {Title, Email} records. The existing SharePoint Person must first be reshaped to {Title, Email} for DefaultSelectedItems. When the user submits the form, the selected {Title, Email} record must be reshaped again into {Claims, DisplayName, Email, ...} for Update.

Thinking in terms of those two boundaries makes most Person-field errors much easier to diagnose.

Extending the Pattern to Multiple Project Managers

To allow more than one project manager:

  1. Configure the SharePoint Project Manager column to allow multiple selections.
  2. Set the Combo box's SelectMultiple property to true.
  3. Return a table of SharePoint Person records from the data card's Update property.

When Items comes from the Person column itself, the records already have the correct schema:

ddlProjectManager.SelectedItems

When Items comes from the controlled Users list:

ForAll(
    ddlProjectManager.SelectedItems As selectedPM,
    With(
        {
            selectedEmail: Lower(selectedPM.Email)
        },
        {
            '@odata.type': "#Microsoft.Azure.Connectors.SharePoint.SPListExpandedUser",
            Claims: "i:0#.f|membership|" & selectedEmail,
            DisplayName: selectedPM.Title,
            Email: selectedEmail
        }
    )
)

When Items comes from Office 365 Users:

ForAll(
    ddlProjectManager.SelectedItems As selectedUser,
    With(
        {
            selectedEmail: Lower(
                Coalesce(
                    selectedUser.Mail,
                    selectedUser.UserPrincipalName
                )
            )
        },
        {
            '@odata.type': "#Microsoft.Azure.Connectors.SharePoint.SPListExpandedUser",
            Claims: "i:0#.f|membership|" & selectedEmail,
            DisplayName: selectedUser.DisplayName,
            Email: selectedEmail
        }
    )
)

For multiple defaults, use a table whose records match Items. With the SharePoint-native approach, the existing multi-person column normally supplies that table directly. With a custom list or Office 365 Users, map or retrieve every existing person in the source schema used by the Combo box.

Practical Checks

When a Person field refuses to save or an existing person does not appear in the Combo box, check:

  1. Is the SharePoint column single-value or multi-value?
  2. Does Update return one record or a table accordingly?
  3. Does the Update record use SharePoint fields such as Claims, DisplayName, and Email?
  4. Does DefaultSelectedItems use the same field names as Items?
  5. Are you using Email for a SharePoint Person record and Mail for an Office 365 Users record?
  6. Could Mail be blank, requiring UserPrincipalName as a fallback?
  7. Is Role a Text column (Role = "PM") or a Choice column (Role.Value = "PM")?

The Rule to Remember

A person is not just an email address in Power Apps. It is a typed record whose shape depends on the connector that returned it.

Use the SharePoint Person column's choices when that meets the requirement. The selected value can usually be saved directly.

When the Combo box uses a controlled list or Office 365 Users, treat the control schema and the SharePoint schema as two separate contracts:

  • Items and DefaultSelectedItems must match each other.
  • The data card's Update value must match the SharePoint Person column.

Once those schemas line up, Person fields become predictable rather than mysterious.