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>
);
}
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ā¦
Your site is like a playground of fun embellishments!
@rembonmike @GMpamwiza @akapeshm
Awesome, Monica!
Nice!
Nice format!