6

I am using react-icons and I have a JSON file as follows:

social: {
  twitter: {
    icon: 'FaTwitter',
    link: 'twitterlink',
  },
  linkedin: {
    icon: 'FaLinkedIn',
    link: 'linkedinlink',
  },
  github: {
    icon: 'FaGithub',
    link: 'githublink',
  },
}

I am trying to dynamically create the icons by looping through the JSON, but I'm having a lot of trouble making it work.

Here are snippets of what I've already tried so far along with the outputs and the errors produced in the console:


React Icons import

import * as FontAwesome from 'react-icons/lib/fa';

1

{Object.keys(social).map(key => {
  let IconName = Component['FontAwesome.' + social[key].icon];

  return (
    <li key={key}>
      <a href={social[key].link} target="_blank" rel="noopener">
        <IconName size="15" />
      </a>
    </li>
  );
})}

Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

Uncaught Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

No output


2

{Object.keys(social).map(key => {
  let IconName = FontAwesome`.${social[key].icon}`;

  return (
    <li key={key}>
      <a href={social[key].link} target="_blank" rel="noopener">
        <IconName size="15" />
        {/* This line produces the same result */}
        {/* {React.createElement(IconName, { size: '15' })} */}
      </a>
    </li>
  );
})}

Uncaught TypeError: __WEBPACK_IMPORTED_MODULE_1_react_icons_lib_fa__ is not a function

No output


3

{Object.keys(social).map(key => {
  let IconName = `FontAwesome.${social[key].icon}`;

  return (
    <li key={key}>
      <a href={social[key].link} target="_blank" rel="noopener">
        <IconName size="15" />
      </a>
    </li>
  );
})}

Warning: <FontAwesome.FaTwitter /> is using uppercase HTML. Always use lowercase HTML tags in React.

Warning: The tag <FontAwesome.FaTwitter> is unrecognized in this browser. If you meant to render a React component, start its name with an uppercase letter.

There are more errors but for FaLinkedIn and FaGithub which are the same.

Output in react dev tool

<li>
  <a href="twitterlink" target="_blank" rel="noopener">
    <Fontawesome.FaTwitter size="15"></Fontawesome.FaTwitter>
  </a>
</li>

HTML output

<li>
  <a href="twitterlink" target="_blank" rel="noopener">
    <fontawesome.fatwitter size="15"></fontawesome.fatwitter>
  </a>
</li>

What I want is something like this:

<FontAwesome.FaTwitter size="15" />

Output in react dev tool

<FaTwitter size="15">
  <IconBase viewBox="0 0 40 40" size="15">
    <svg fill="currentColor" preserveAspectRatio="xMidYMid meet" height="15" width="15" viewBox="0 0 40 40" style="vertical-align: middle;">
      <g>
        <path d="m37.7 9.1q-1.5 2.2-3.7 3.7 0.1 0.3 0.1 1 0 2.9-0.9 5.8t-2.6 5.5-4.1 4.7-5.7 3.3-7.2 1.2q-6.1 0-11.1-3.3 0.8 0.1 1.7 0.1 5 0 9-3-2.4-0.1-4.2-1.5t-2.6-3.5q0.8 0.1 1.4 0.1 1 0 1.9-0.3-2.5-0.5-4.1-2.5t-1.7-4.6v0q1.5 0.8 3.3 0.9-1.5-1-2.4-2.6t-0.8-3.4q0-2 0.9-3.7 2.7 3.4 6.6 5.4t8.3 2.2q-0.2-0.9-0.2-1.7 0-3 2.1-5.1t5.1-2.1q3.2 0 5.3 2.3 2.4-0.5 4.6-1.7-0.8 2.5-3.2 3.9 2.1-0.2 4.2-1.1z">
        </path>
      </g>
    </svg>
  </IconBase>
</FaTwitter>

HTML Output

<svg fill="currentColor" preserveAspectRatio="xMidYMid meet" height="15" width="15" viewBox="0 0 40 40" style="vertical-align: middle;">
  <g>
    <path d="m37.7 9.1q-1.5 2.2-3.7 3.7 0.1 0.3 0.1 1 0 2.9-0.9 5.8t-2.6 5.5-4.1 4.7-5.7 3.3-7.2 1.2q-6.1 0-11.1-3.3 0.8 0.1 1.7 0.1 5 0 9-3-2.4-0.1-4.2-1.5t-2.6-3.5q0.8 0.1 1.4 0.1 1 0 1.9-0.3-2.5-0.5-4.1-2.5t-1.7-4.6v0q1.5 0.8 3.3 0.9-1.5-1-2.4-2.6t-0.8-3.4q0-2 0.9-3.7 2.7 3.4 6.6 5.4t8.3 2.2q-0.2-0.9-0.2-1.7 0-3 2.1-5.1t5.1-2.1q3.2 0 5.3 2.3 2.4-0.5 4.6-1.7-0.8 2.5-3.2 3.9 2.1-0.2 4.2-1.1z">
    </path>
  </g>
</svg>

Is what I'm trying to do possible? Are there any workarounds or another way of doing it?

There are similar questions are StackOverflow but none seems to be working for me, that's why I asking a new one. I've also tried googling the errors but no luck there either.

Yannick
  • 63
  • 1
  • 2
  • 8

1 Answers1

13

Here is how to create react-icons dynamically given the name of the icon:

import React from "react";
import { render } from "react-dom";
import * as FontAwesome from "react-icons/lib/fa";

const Icon = props => {
  const { iconName, size, color } = props;
  const icon = React.createElement(FontAwesome[iconName]);
  return (
    <div style={{ fontSize: size, color: color }}>{icon}</div>
  );
};

Once you have this icon wrapper, just use it as a normal React component:
<Icon iconName={"FaBeer"} size={12} color="orange" />
The icon name should follows MixedCaps naming conversion.

This link is a codesandbox demo of the code above: https://codesandbox.io/s/o715x22m4z

FisNaN
  • 2,517
  • 2
  • 24
  • 39
  • Thank you, this worked. I also wrote one of the icon names incorrectly. I wrote FaLinkedIn instead of FaLinkedin which was throwing an error as well. – Yannick Mar 21 '18 at 13:14
  • Is there a way to do this without loading all the icons (bandwidth concerns)? – Biaspoint May 16 '23 at 17:38