Enhancing Navigations with Icons

There isn’t much to say about navigations and their purpose: Basically, they’re collections of links pointing to subsections or individual pages of a website, allowing visitors to access those pages directly. Usually, the more relevant or important these links are, the more prominently they’re placed and the more effort is put into their appearance. Ideally, a main navigation (often referred to as menu) clearly indicates how a website is structured and aims at guiding visitors in their endeavor to explore and utilize a site.

That said, it is obvious that, next to a well thought out site structure, the clearness and pointedness of menu items is essential for them to be grasped quickly with respect to the content they link to. Using speaking icons in navigation items, either in conjunction with text or stand-alone, can be extremely helpful to reaching this goal. You’ll be rewarded with a stronger increase in website traffic if you do.

In this guide, we are going to explain to you the basic principles of building richer navigations with Scrivito by making menu items more expressive through icons. For this walkthrough, you will need some basic knowledge of Scrivito’s working principles.

First, let’s spend a minute or two on answering a pivotal question: Where do the items included in a navigation come from?

Determining the navigation items

So how can we determine the items to show up in a navigation? There’s at least three approaches:

Maintain the items manually

Scrivito features two attribute types, linklist and referencelist, for manually specifying and maintaining links. Both are well suited for providing navigations. linklist attributes accommodate external and internal links, while referencelists are limited to internal links (which makes them easier to handle).

In the Scrivito Example App, the GalleryWidget makes use of a referencelist for specifying the images to present.

Use the parent-child relationship between pages

Scrivito supports organizing pages hierarchically (based on their path). For a (parent) page with child pages, the children method returns exactly those subpages. For conveniently having a parent’s children rendered, the Scrivito.ChildListTag React component is available.

The Example App’s main navigation uses this component as it is based on the pages sitting directly underneath the root page. If you would like to create such a navigation from scratch, have a look at our Building a Child Navigation tutorial.

Use a search

If the navigation should be made up of all items that meet specific criteria, like “all pages tagged ‘department’”, you can use a search to find them. In the Example App, the blog overview component finds blogposts by their CMS object class, BlogPost.

Adding icons to the Example App’s main navigation

The Scrivito Example App’s navigation is quite extensive, not only because it includes a logo, a search button, sticks to the top, and collapses on small screens. It also takes account of landing pages on which all those nice features, except for the logo, are masked out.

The navigation code can be found in “src/Components/Navigation.js”. It makes use of the files in the “src/Components/Navigation” directory. We won’t explain the whole navigation system here but focus on the code that renders single items because that’s the part we want to tweak.

In the Example App, single navigation items are rendered by the NavSingleChild component:

src/Components/Navigation/NavChild.js
Copy
const NavSingleChild = Scrivito.connect(({ child, open, ...otherProps }) => {
  const classNames = ["nav-item"];
  if (open) {
    classNames.push("open");
  }
  if (isActive(child)) {
    classNames.push("active");
  }

  return (
    <li className={classNames.join(" ")} {...otherProps}>
      <Scrivito.LinkTag to={child} className="nav-link">
        {child.get("title") || "<untitled>"}
      </Scrivito.LinkTag>
    </li>
  );
});

The NavSingleChild component is rendered from within two components, NavChild for top-level menu items without children (e.g. Product), and Dropdown for the children of top-level items (e.g. “About”). For each child, the above code outputs an <li> element in which a Scrivito.LinkTag links the title of the child to its page. The enclosing <ul> element is provided by parent components, e.g. Scrivito.ChildListTag.

Prerequisites

To have an icon rendered in combination with the title, we need to be able to specify the icon to use for a page. For this, we’ll first add an enum attribute, menuIcon, to the Page object class and give it a couple of Font Awesome icons included in the Example App:

src/Objs/Page/PageObjectClass.js
Copy
// Imports

const Page = Scrivito.provideObjClass("Page", {
  attributes: {
    ...defaultPageAttributes,
    childOrder: "referencelist",
    ...metaDataAttributes,
    menuIcon: [
      "enum", {
        values: [
          "fa-globe",
          "fa-user",
          "fa-paper-plane-o",
          "fa-cogs",
          "fa-star-o",
          "fa-heart-o"
        ]
      }
    ]
  }
});

// ...

Next, to enable editors to pick one of these icons (which assigns it to menuIcon), we’ll extend the editing configuration of the Page class accordingly:

src/Objs/Page/PageEditingConfig.js
Copy
// Imports

Scrivito.provideEditingConfig("Page", {
  title: "Page",
  thumbnail: PageObjIcon,
  attributes: {
    ...defaultPageEditingConfigAttributes,
    ...metaDataEditingConfigAttributes,
    menuIcon: {
      title: "Menu icon",
      description: "Default: none",
      values: [
        { value: "fa-globe", title: "Globe" },
        { value: "fa-user", title: "User" },
        { value: "fa-paper-plane-o", title: "Plane" },
        { value: "fa-cogs", title: "Cogs" },
        { value: "fa-star-o", title: "Star" },
        { value: "fa-heart-o", title: "Heart" },
      ],
    },
  },
  properties: ["menuIcon", ...defaultPageProperties],
  propertiesGroups: [socialCardsPropertiesGroup, metaDataPropertiesGroup],
  initialContent: {
    ...defaultPageInitialContent,
    ...metaDataInitialContent,
  },
});

We’ve added menuIcon to the attributes and the properties keys, causing the attribute to become editable on the properties dialog of Pages. Try it out by clicking one of the navigation items at the top, e.g. “Our Work” in “About”, then open the page properties via the top-right menu and select a menu icon. The Example App includes a lot of of icon images that are ideal for this purpose; see “src/assets/stylesheets/fontawesome/_icons.scss” for details.

The above changes should also be applied to the class and editing configuration definitions of other pages you might want to add to the main navigation as subpages, e.g. LandingPage (there already is one in the “Pages & Widgets” submenu).

Rendering the icons

Now, as indicated above, to have the icons rendered, we’ll extend the NavSingleChild component so that it uses the menuIcon attribute:

src/Components/Navigation/NavChild.js
Copy
const NavSingleChild = Scrivito.connect(({ child, open, ...otherProps }) => {
  const classNames = ["nav-item"];
  if (open) {
    classNames.push("open");
  }
  if (isActive(child)) {
    classNames.push("active");
  }

  var menuIcon;

  if (menuIcon = child.get('menuIcon')) {
    menuIcon = <i className={`fa ${menuIcon} fa-1x fa-fw text-muted mr-2`} aria-hidden="true"></i>;
  }

  return (
    <li className={classNames.join(" ")} {...otherProps}>
      <Scrivito.LinkTag to={child} className='nav-link text-left text-nowrap'>
        {menuIcon}
        {child.get("title") || "<untitled>"}
      </Scrivito.LinkTag>
    </li>
  );
});

The page to be represented in the navigation is passed in as the child argument. Then:

  • Some CSS classes are collected in classNames depending on the menu and menu item state.
  • In the middle part that we’ve added (starting at var menuIcon;), the menuIcon attribute of the child page is fetched. If an icon is set, the markup is defined based on it.
  • In the bottom part, we’ve inserted the menuIcon markup as well as added CSS classes for left-aligning and not wrapping the menu item texts.

All of a sudden, we’re done. :)

Summed up...

As a result of our efforts, the submenu items of the main navigation can now be equipped with individual icons. On the model and editing side, this was achieved by introducing another attribute, menuIcon, to the Page class and, respectively, its editing configuration. On the rendering side, we’ve used this attribute to determine the specified menu icon image and generate the markup for it.

If you insist on having icons rendered for top-level menu items with children as well, consider making the code that handles the icon a function, which you could then call in the Dropdown component.

For offering more icons or enhancing the way they are presented on the properties dialog, have a look at Customizing Page and Widget Property Editing.