React icon
• šŸæ 4 min read

How To Render Relevant Icons Based on Content

Animated Monica

By: Monica Powell


This article walks through how I display relevant, themed icons when linking to content on this site based on the topic or type of content. If you’ve visited the homepage of this site, I use a variation of this component to display my recent content, featured content, and recent video lessons.

ArticleList: Rendering Article Titles + Icons

The logic for displaying article titles alongside a relevant icon is constructed within an <ArticleList/> component. Below is an example of a fully functioning, interactive <ArticleList/> component (thanks to MDX):


In my actual site the article data is programmatically passed in from the result of a GraphQL query, however, a similar component can be used regardless of how your website handles data. I used the below JSX markup with hard-coded data to render the above instance of the <ArticleList/> component:

<ArticleList
  articles={[
    {
      slug: "/blog/create-gatsby-blog-search-tutorial/",
      tags: ["gatsby"],
      title: "How to Add Search Functionality to a Gatsby Blog",
    },
    {
      slug: "/blog/2020-01-29-automating-file-creation-with-javascript/",
      tags: ["javascript"],
      title: "Automating File Creation With JavaScript",
    },
    {
      slug: "/blog/how-to-create-a-github-profile-readme/",
      tags: ["Git/GitHub"],
      title: "How To Create A GitHub Profile README",
    },
  ]}
/>

Essentially the <ArticleList/> component maps through each article in the articles array and displays the article title along with a link to the article and an article icon based on the article tags. A simplified version of the render of <ArticleList/> resembles the below code. Note: Whenever mapping through items to render items in React you should use a unique key in order for React to be able to efficiently differentiate between different items within the generated list:

{
  articles.map(({ slug, tags, title }, index) => (
    <div key={`${index}-${slug}`}>
      <ArticleIcon tags={tags} />
      <Link to={slug} className="article-link">
        {title}
      </Link>
    </div>
  ));
}

ArticleIcon: Returning the Relevant Icon

The logic to determine which icon should render for a given article based on its tags is handed off from the <ArticleList/> component to the <ArticleIcon/> component. Let’s take a closer look at the <ArticleIcon/> component.

Setting up Icons

The <ArticleIcon/> component imports multiple SVG image files for each of the potential icons that will be rendered:

import GitHubIcon from "./icons/github.svg";
import ReactIcon from "./icons/react.svg";
import JavascriptIcon from "./icons/javascript.svg";
import PenIcon from "./icons/pen.svg";

Then within the ArticleIcon component there’s an object that contains the imported icons with key value pairs that look like [tag]: icon. I have intentionally omitted the PenIcon from this object as it is the default icon that is displayed when there is not a better matching icon available for a given set of tags. I also decided to structure the object this way so that icons could quickly be retrieved based on their tag name which is the name of the properties in the icons object. In the below instance I have two separate keys for Git and GitHub since either tag should be associated with the GitHubIcon.

export default function ArticleIcon({ tags }) {
  const icons = {
    git: GitHubIcon,
    github: GitHubIcon,
    react: ReactIcon,
    javascript: JavascriptIcon,
  };
}

Finding the Most Relevant Icon

After initializing the icons object the method .find() is used to locate the first instance of a tag within the array of the tags (passed in via props) that matches a tag within the icons object. Since .find() returns the first instance that is found if an array of tags contains multiple tags that have icons in the icons object, only the first tag that matches an icon in the icons object will be returned:

const articleTagWithIcon = (tags || []).find((tag) => icons[tag.toLowerCase()]);

If there is an icon associated with any of the article tags then the articleIcon is set to the value of icons[articleTagWithIcon.toLowerCase()] or else the icon will be set to the default icon which is the PenIcon.

const articleIcon = articleTagWithIcon
  ? icons[articleTagWithIcon.toLowerCase()]
  : PenIcon;

Finally we can return an image in the render of the ArticleIcon:

return (
  <img
    src={articleIcon}
    alt={articleTagWithIcon ? `${articleTagWithIcon} icon` : `pen icon`}
  />
);

Summary

This article went over how to create the logic for a component that renders different images based on the data that is passed in. I used CSS flex for the majority of the styling of this component, if you are interested in learning more about the styling behind the <ArticleList/> inspect the <ArticleList/> on my website! For sake of clarity, I may have omitted some markup or classes that were used to style the component from this article.

Final Code

All together the complete ArticleIcon.jsx file looks like:

import React from "react";
import GitHubIcon from "./icons/github.svg";
import ReactIcon from "./icons/react.svg";
import JavascriptIcon from "./icons/javascript.svg";
import PenIcon from "./icons/pen.svg";

export default function ArticleIcon({ tags }) {
  const icons = {
    git: GitHubIcon,
    github: GitHubIcon,
    react: ReactIcon,
    javascript: JavascriptIcon,
  };

  const articleTagWithIcon = (tags || []).find(
    (tag) => icons[tag.toLowerCase()],
  );

  const articleIcon = articleTagWithIcon
    ? icons[articleTagWithIcon.toLowerCase()]
    : PenIcon;

  return (
    <span className="article-icon">
      <img
        src={articleIcon}
        alt={articleTagWithIcon ? `${articleTagWithIcon} icon` : `pen icon`}
      />
    </span>
  );
}

Likes & Reposts

Shared by :party-corgi:Shared by creeeShared by EmmanuelShared by StuShared by S.Shared by FabianShared by VarunShared by DivineShared by UcheShared by ElijahShared by egghead.ioShared by Dwayne

+72

Discussion

  • mentioned on November 10, 2020
    via

    Looking for a way to display relevant, themed icons when linking to content on your site? @waterproofheart gives a really simple and elegant tutorial of how to set one up. Follow the link to learn more: aboutmonica.com/blog/how-to-re…

  • replied on September 14, 2020
    via

    Your site is like a playground of fun embellishments!

  • replied on September 13, 2020
    via

    @rembonmike @GMpamwiza @akapeshm

  • replied on September 13, 2020
    via

    Awesome, Monica!

  • replied on September 13, 2020
    via

    Nice!

  • replied on September 12, 2020
    via

    Nice format!