🍿 3 min. read
How To Render Relevant Icons Based on Content
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<ArticleList2 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 = articleTagWithIcon2 ? icons[articleTagWithIcon.toLowerCase()]3 : PenIcon
Finally we can return an image in the render of the ArticleIcon:
1return (2 <img3 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 = articleTagWithIcon18 ? icons[articleTagWithIcon.toLowerCase()]19 : PenIcon20
21 return (22 <span className="article-icon">23 <img24 src={articleIcon}25 alt={articleTagWithIcon ? `${articleTagWithIcon} icon` : `pen icon`}26 />27 </span>28 )29}
This article was published on September 12, 2020.