logo
Published on

PnP Listview and contextual menu in the SharePoint Framework (SPFx) web part

This article explains how to implement the PnP ListView and Contextual Menu in the SharePoint Framework (SPFx) web part.
It allows you to display files in a list view and add actions such as open, download, and delete using the contextual menu options.


📦 Install dependencies

npm install @pnp/sp --save
npm install office-ui-fabric-react --save
npm install moment --save

🧩 filemenu.tsx

import * as React from 'react';
import { IconButton } from 'office-ui-fabric-react';
import { ContextualMenuItemType } from 'office-ui-fabric-react/lib/ContextualMenu';
import { sp } from "@pnp/sp";
import "@pnp/sp/webs";
import "@pnp/sp/lists";
import "@pnp/sp/items";
import { autobind } from 'office-ui-fabric-react/lib/Utilities';
 
export interface IfilemenuProps {
    item: any;
    context: any;
    ondatachange: any;
}
 
export class filemenu extends React.Component<IfilemenuProps, {}> {
 
    public constructor(props: IfilemenuProps) {
        super(props);
        sp.setup({
            spfxContext: this.props.context
        });
        this.state = {
            panelOpen: false
        };
    }
 
    public render() {
        return (
            <div>
                <IconButton id='ContextualMenuButton1'
                    text=''
                    width='30'
                    split={false}
                    iconProps={{ iconName: 'MoreVertical' }}
                    menuIconProps={{ iconName: '' }}
                    menuProps={{
                        shouldFocusOnMount: true,
                        items: [
                            {
                                key: 'action1',
                                name: 'Open in new tab',
                                onClick: this.handleClick.bind(this, "open", this.props.item)
                            },
                            {
                                key: 'divider_1',
                                itemType: ContextualMenuItemType.Divider
                            },
                            {
                                key: 'action2',
                                name: 'Download',
                                onClick: this.handleClick.bind(this, "download", this.props.item)
                            },
                            {
                                key: 'action3',
                                name: 'Delete',
                                onClick: this.handleClick.bind(this, "delete", this.props.item)
                            },
                            {
                                key: 'disabled',
                                name: 'Disabled action',
                                disabled: true,
                                onClick: () => console.error('Disabled action should not be clickable.')
                            }
                        ]
                    }} />
            </div>
        );
    }
 
    @autobind
    private async handleClick(actionType: string, seletedfile: any, event) {
        if (actionType === 'open') {
            window.open(
                window.location.protocol + "//" + window.location.host + seletedfile.ServerRelativeUrl + "?web=1",
                '_blank'
            );
        }
        else if (actionType === 'download') {
            window.open(
                window.location.protocol + "//" + window.location.host + seletedfile.ServerRelativeUrl + "?web=0",
                '_blank'
            );
        }
        else if (actionType === 'delete') {
            let list = sp.web.lists.getByTitle("Policies");
            await list.items.getById(seletedfile["ListItemAllFields.ID"]).delete();
            this.props.ondatachange();
        }
    }
}

🧩 SpfxPnpListviewContextualmenu.tsx

import * as React from 'react';
import { IViewField } from "@pnp/spfx-controls-react/lib/ListView";
import { filemenu, IfilemenuProps } from './filemenu';
import { sp } from "@pnp/sp";
import "@pnp/sp/webs";
import "@pnp/sp/lists";
import "@pnp/sp/items";
import * as moment from 'moment';

export default class SpfxPnpListviewContextualmenu extends React.Component<ISpfxPnpListviewContextualmenuProps, ISpfxPnpListviewContextualmenuState> {
  constructor(props: ISpfxPnpListviewContextualmenuProps, state: ISpfxPnpListviewContextualmenuState) {
    super(props);
    sp.setup({
      spfxContext: this.props.context
    });
    var _viewFields: IViewField[] = [
      {
        name: "Name",
        linkPropertyName: "ServerRelativeUrl",
        displayName: "Name",
        sorting: true,
        minWidth: 250,
      },
      {
        name: "",
        sorting: false,
        maxWidth: 40,
        render: (rowitem: any) => {
          const element: React.ReactElement<IfilemenuProps> = React.createElement(
            filemenu,
            {
              item: rowitem,
              context: this.props.context,
              ondatachange: this._getfiles
            }
          );
          return element;
        }
      },
      {
        name: "Author.Title",
        displayName: "Author",
        sorting: false,
        minWidth: 180,
        render: (item: any) => {
          const authoremail = item['Author.UserPrincipalName'];
          return <a href={'mailto:' + authoremail}>{item['Author.Title']}</a>;
        }
      },
      {
        name: "TimeCreated",
        displayName: "Created",
        minWidth: 150,
        render: (item: any) => {
          const created = item["TimeCreated"];
          if (created) {
            const createdDate = moment(created);
            return <span>{createdDate.format('DD/MM/YYYY HH:mm:ss')}</span>;
          }
        }
      }
    ];
    this.state = { items: [], viewFields: _viewFields };
    this._getfiles();
  }
}

🚀 Deploy the solution

Build, bundle, and package the SPFx web part:

gulp build
gulp bundle --ship
gulp package-solution --ship

Upload the .sppkg file to your App Catalog, deploy it, and add the PnP ListView Contextual Menu web part to your SharePoint page.


📂 GitHub Source

View full SPFx project on GitHub:PnP Listview and contextual menu in the SharePoint Framework (SPFx) web part

GitHub

✅ Summary

This example shows how to combine PnP ListView and Fluent UI Contextual Menu for SharePoint to display, open, download, and delete files easily.
It provides a powerful and modern user experience for document libraries using the SPFx framework.

Calendar IconBook a demo