🍿 3 min. read

How To Render Relevant Icons Based on Content

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:

1<ArticleList
2 articles={[
3 {
4 slug: "/blog/create-gatsby-blog-search-tutorial/",
5 tags: ["gatsby"],
6 title: "How to Add Search Functionality to a Gatsby Blog",
7 },
8 {
9 slug: "/blog/2020-01-29-automating-file-creation-with-javascript/",
10 tags: ["javascript"],
11 title: "Automating File Creation With JavaScript",
12 },
13 {
14 slug: "/blog/how-to-create-a-github-profile-readme/",
15 tags: ["github"],
16 title: "How To Create A GitHub Profile README",
17 },
18 ]}
19/>

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:

1{
2 articles.map(({ slug, tags, title }, index) => (
3 <div key={`${index}-${slug}`}>
4 <ArticleIcon tags={tags} />
5 <Link to={slug} className="article-link">
6 {title}
7 </Link>
8 </div>
9 ))
10}

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:

1import GitHubIcon from "./icons/github.svg"
2import ReactIcon from "./icons/react.svg"
3import JavascriptIcon from "./icons/javascript.svg"
4import 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.

1export default function ArticleIcon({ tags }) {
2 const icons = {
3 git: GitHubIcon,
4 github: GitHubIcon,
5 react: ReactIcon,
6 javascript: JavascriptIcon,
7 }
8}

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:

1const 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.

1const articleIcon = articleTagWithIcon
2 ? icons[articleTagWithIcon.toLowerCase()]
3 : PenIcon

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

1return (
2 <img
3 src={articleIcon}
4 alt={articleTagWithIcon ? `${articleTagWithIcon} icon` : `pen icon`}
5 />
6)

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:

1import React from "react"
2import GitHubIcon from "./icons/github.svg"
3import ReactIcon from "./icons/react.svg"
4import JavascriptIcon from "./icons/javascript.svg"
5import PenIcon from "./icons/pen.svg"
6
7export default function ArticleIcon({ tags }) {
8 const icons = {
9 git: GitHubIcon,
10 github: GitHubIcon,
11 react: ReactIcon,
12 javascript: JavascriptIcon,
13 }
14
15 const articleTagWithIcon = (tags || []).find(tag => icons[tag.toLowerCase()])
16
17 const articleIcon = articleTagWithIcon
18 ? icons[articleTagWithIcon.toLowerCase()]
19 : PenIcon
20
21 return (
22 <span className="article-icon">
23 <img
24 src={articleIcon}
25 alt={articleTagWithIcon ? `${articleTagWithIcon} icon` : `pen icon`}
26 />
27 </span>
28 )
29}

This article was published on September 12, 2020.


Don't be a stranger! 👋🏾

Thanks for reading "How To Render Relevant Icons Based on Content". Join my mailing list to be the first to receive my newest web development content, my thoughts on the web and learn about exclusive opportunities.

     

    I won’t send you spam. Unsubscribe at any time.

    Webmentions

    156
    • Peter Fields
    • Oleg Sbulog
    • jade
    • Sean Keever 🌦️
    • Paul Melero
    • Jason Lengstorf
    • journie
    • Kristian Heruc
    • Naya Moss is working on #frauvislowcodehack
    • Eric Wallace
    • Joe Previte
    • TheRealDine
    • Laureni
    • Vinicius Pacheco
    • Tom Hermans🤘
    • Jorge Berenguer
    • Antonio Laguna ツ
    • Angel Juarez
    • Mohammed Zeeshan
    • Mike, but wearing a mask
    • Kenneth Fechter
    • Uche Emordi
    • Dwayne
    • Prince Sumberia
    • Anthony Harvey
    • Geekintheflesh
    • CY is here 👩‍💻🚀
    • Alex Crocker 🏳️‍🌈
    • Divine 🛸
    • Laurie
    • Philipp Hamerle
    • Todd Morey
    • David E. Patrick
    • Fatou
    • Lutaaya Brian Ivan
    • حامد سهیلی
    • Nika Zawila
    • Tom Hermans🤘
    • Jesús Macedo 🤘🏻
    • Fabian Brash
    • +29