Search Veni, Vidi, Vici

Tip: Implementing 'Nav' Office Fabric UI React Component

This post is meant to be a quick supplement to the documentation provided by Microsoft around the Nav component of the Fluent UI. This Nav component gives you a control that you either create URL links or maybe more commonly, support navigation via code. For general links, where the URL is either a route or some other page, the implementation of the INavLinkGroup[] and INavLink is quite straight forward, just provide a Key, Name, and URL with a couple other optional parameters. For programmatic support, the documentation provides a solution but as it turns out that implementation is misleading. I was finding that my nav items that needed to execute a bit of code would sometimes execute that code twice. As it turns out I wasn’t using it right, so let me help clarify by showing you what I found.

Documented Implementation

 1<Nav
 2  groups={[
 3 {
 4   links: [
 5  {
 6    name: 'Home',
 7    url: 'https://example.com',
 8    links: [
 9   {
10     name: 'Activity',
11     url: 'https://msn.com',
12     key: 'key1'
13   },
14   {
15     name: 'News',
16     url: 'https://msn.com',
17     key: 'key2'
18   }
19    ],
20    isExpanded: true
21  },
22  { name: 'Documents', url: 'https://example.com', key: 'key3', isExpanded: true },
23  { name: 'Pages', url: 'https://msn.com', key: 'key4' },
24  { name: 'Notebook', url: 'https://msn.com', key: 'key5' },
25  { name: 'Long Name Test for ellipse', url: 'https://msn.com', key: 'key6' },
26  {
27    name: 'Edit',
28    url: 'https://cnn.com',
29    onClick: this._onClickHandler2,
30    icon: 'Edit',
31    key: 'key8'
32  },
33  {
34    name: 'Delete',
35    url: 'https://cnn.com',
36    onClick: this._onClickHandler2,
37    iconProps: { iconName: 'Delete' },
38    key: 'key9'
39  }
40   ]
41 }
42  ]}
43  expandedStateText={'expanded'}
44  collapsedStateText={'collapsed'}
45  selectedKey={'key3'}
46/>

Note the code on lines 29 and 36. Those are INavLink entries that include the “onClick” event. So when I implemented similar Nav items I implemented them the same way. After playing around with it a little I realized my issue with some code executing twice when the link was clicked and realized that the proper implementation is to leverage the onLinkClick property by which you can bind an event handler to the Nav component to handle link clicks. The signature for that method includes the HTML element as well as the INavLink item that was clicked. Using this allows us to redirect to our other code to handle those Nav items that require a little more programmatic support.

In my implementation the Nav is hidden until the user clicks on a menu icon. I decided to implement with a simple switch statement, where the default case hides the menu by changing my state property that displayed it in the first place (I handle hiding the menu for each of the other menu options in their specific implementations as I’m often changing some other aspect of the state and want to try and consolidate these calls as much as possible). Ok, so let me just show you how I would implement the above example:

Updated Implementation

Note in lines 28 and 34 I simply set the url to an empty string. Then, later on line 41 I hook the component up to my click handler.

 1<Nav
 2  groups={[
 3 {
 4   links: [
 5  {
 6    name: 'Home',
 7    url: 'https://example.com',
 8    links: [
 9   {
10     name: 'Activity',
11     url: 'https://msn.com',
12     key: 'key1'
13   },
14   {
15     name: 'News',
16     url: 'https://msn.com',
17     key: 'key2'
18   }
19    ],
20    isExpanded: true
21  },
22  { name: 'Documents', url: 'https://example.com', key: 'key3', isExpanded: true },
23  { name: 'Pages', url: 'https://msn.com', key: 'key4' },
24  { name: 'Notebook', url: 'https://msn.com', key: 'key5' },
25  { name: 'Long Name Test for ellipse', url: 'https://msn.com', key: 'key6' },
26  {
27    name: 'Edit',
28    url: '',
29    icon: 'Edit',
30    key: 'key8'
31  },
32  {
33    name: 'Delete',
34    url: '',
35    iconProps: { iconName: 'Delete' },
36    key: 'key9'
37  }
38   ]
39 }
40  ]}
41  onLinkClick={this._onNavClick}
42  expandedStateText={'expanded'}
43  collapsedStateText={'collapsed'}
44  selectedKey={'key3'}
45/>
 1private _onNavClick(e: React.MouseEvent<HTMLElement>, item: INavLink): void {
 2  switch(item.key){
 3    case "key8":
 4      this._onEdit();
 5      break;
 6    case "key9":
 7      this._onDelete();
 8      break;
 9    default:
10      this.setState({showPlaylistMenu: false});
11      break;
12  }
13}

Hope this helps in your implementations, Happy Coding!