Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamically render icons by a string name #481

Open
x10geeky opened this issue Apr 20, 2024 · 1 comment
Open

Dynamically render icons by a string name #481

x10geeky opened this issue Apr 20, 2024 · 1 comment

Comments

@x10geeky
Copy link

How can I dynamically render icons in React based on a string value?

@rektdeckard
Copy link
Member

rektdeckard commented Apr 20, 2024

You've got a few choices. You can import the whole library and index into it by component name:

import * as P from "@phosphor-icons/react";

function App() {
  const Avocado = P['Avocado'];
  return <Avocado weight="fill" color="darkolivegreen" />;
}

This has perf consequences, but I'd do this for something like an electron or react native app, where bundle size is not an issue and the simplicity is nicer.

Another way (for which the exact details depend on your build tools and specific environment) is with dynamic imports, using code-splitting and Suspense to lazily import icons as needed. This example works with React + Vite:

import { lazy, Suspense } from 'react';
import type { IconProps } from '@phosphor-icons/react';

// This is essentially a map of relative paths to dynamic import functions,
// but since we use named exports we need to transform them to default exports.
// Most bundlers don't support template strings in dynamic imports, so we essentially
// let it code-split the whole Phosphor lib and allow them to be loaded at runtime.
const importMap = Object.entries(import.meta.glob("../node_modules/@phosphor-icons/react/dist/ssr/*.mjs"))
  .reduce((acc, [path, fn]) => {
    acc[path] = (name) => fn().then((mod) => ({ default: mod[name] }));
    return acc;
  }, {});

function relativePathForIcon(name: string) {
  return `../node_modules/@phosphor-icons/react/dist/ssr/${name}.mjs`;
}

export function LazyIcon(props: IconProps & { name: string }) {
  const { name, ...iconProps } = props;
  const Icon = lazy(() => importMap[relativePathForIcon(name)](name));

  return (
    <Suspense fallback={null}>
      <Icon {...iconProps} />
    </Suspense>
  );
}

// THEN IN YOUR APP
function App() {
  return <LazyIcon name="Avocado" weight="fill" color="darkolivegreen" />;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants