Louis Emard
Louis Emard

Reputation: 171

Antd icon type from string in v4

I have to upgrade antd from v3 to v4, previously we used to show some icons from string passed as prop like this :

 <Icon type={props.icon} />

Is there a way to achieve something like this in antd v4 with the new Icon system ? I know the existence of '@ant-design/compatible' but the migration was made to reduce the bundle size so i'd like to avoid this solution.

Edit : I just changed the way I use icons, in my config file I import the icons and pass them to my generator like this : icon = {props.icon} instead of the previous <Icon type={props.icon} />.

Upvotes: 11

Views: 10281

Answers (6)

Mohamed Aarab
Mohamed Aarab

Reputation: 946

With the help of @Cea's approach, I have managed to set Icons dynamically as shown here:

import * as AntdIcons from '@ant-design/icons';

const CustomIcon=(type:string)=>{
    const AntdIcon= AntdIcons[type] // not AntdIcons[iconDetails.render] as @Cea mention;
    return <AntdIcon/>
}

Then inside my loop menu, I retrieve the Icon name an pass it to the CustomIcon function as a parameter.

I hope this helps someone

Upvotes: 1

Mauricio Florez
Mauricio Florez

Reputation: 1132

I was using the response by @rikesh-lal-shrestha but I need pass additional props, this is my solution based in @doctorgu response

//DynamicIcon.jsx

import {
  QuestionOutlined,
  DashboardOutlined,
  SmileOutlined,
  FormOutlined,
  TabletOutlined,
  ProfileOutlined,
  CheckCircleOutlined,
  WarningOutlined,
  UserOutlined,
  HighlightOutlined,
  TableOutlined,
  CloseCircleOutlined,
} from '@ant-design/icons';
import * as PropTypes from 'prop-types';

const IconSelector = ({ type, ...rest }) => {
  const getIcon = (iconType) => ({
    QuestionOutlined: <QuestionOutlined {...rest} />,
    DashboardOutlined: <DashboardOutlined {...rest} />,
    SmileOutlined: <SmileOutlined {...rest} />,
    FormOutlined: <FormOutlined {...rest} />,
    TabletOutlined: <TabletOutlined {...rest} />,
    ProfileOutlined: <ProfileOutlined {...rest} />,
    CheckCircleOutlined: <CheckCircleOutlined {...rest} />,
    WarningOutlined: <WarningOutlined {...rest} />,
    UserOutlined: <UserOutlined {...rest} />,
    HighlightOutlined: <HighlightOutlined {...rest} />,
    CloseCircleOutlined: <CloseCircleOutlined {...rest} />,
    TableOutlined: <TableOutlined {...rest} />,
  }[iconType]);

  return getIcon(type) || <QuestionOutlined {...rest} />;
};

IconSelector.propTypes = {
  type: PropTypes.string,
};

export default IconSelector;

Usage

<DynamicIcon type={icon} style={{ fontSize: 24, color: color || 'red' }} />

Upvotes: 0

CeamKrier
CeamKrier

Reputation: 839

You also can import all the files from antd/icons as:

import * as AntdIcons from '@ant-design/icons';

Then you can access all the available icons from AntdIcons variable as follows:

const AntdIcon = AntdIcons[iconDetails.render];

Where iconDetails.render is a variable that is something like HomeOutlined, SettingsOutlined etc..

Then finally, you can render your components as

<AntdIcon />

Upvotes: 4

doctorgu
doctorgu

Reputation: 634

I am here to find a way to dynamically load icon for menu. And I don't like other solution. So I decided to create another solution.

My solution is simple. Actually it is not dynamic, it choose already loaded component. But it is safe for Webpack because it will include only used component in source code. It means result size is smaller than including over 700 count of all svg files in published folder.

// IconSelector.tsx

import React from 'react';
import {
  QuestionOutlined,
  DashboardOutlined,
  SmileOutlined,
  FormOutlined,
  TabletOutlined,
  ProfileOutlined,
  CheckCircleOutlined,
  WarningOutlined,
  UserOutlined,
  HighlightOutlined,
  TableOutlined,
} from '@ant-design/icons';

interface IconSelectorProps {
  type: string;
}

const IconSelector: React.FC<IconSelectorProps> = (props: IconSelectorProps) => {
  const Icons = {
    QuestionOutlined: <QuestionOutlined />,
    DashboardOutlined: <DashboardOutlined />,
    SmileOutlined: <SmileOutlined />,
    FormOutlined: <FormOutlined />,
    TabletOutlined: <TabletOutlined />,
    ProfileOutlined: <ProfileOutlined />,
    CheckCircleOutlined: <CheckCircleOutlined />,
    WarningOutlined: <WarningOutlined />,
    UserOutlined: <UserOutlined />,
    HighlightOutlined: <HighlightOutlined />,
    TableOutlined: <TableOutlined />,
  };

  const getIcon = (type: string) => {
    // Default Icon when not found
    let comp = <QuestionOutlined />;

    let typeNew = type;

    // Default is Outlined when no theme was appended (ex: 'smile')
    if (!typeNew.match(/.+(Outlined|Filled|TwoTone)$/i)) {
      typeNew += 'Outlined';
    }

    // If found by key then return value which is component
    const found = Object.entries(Icons).find(([k]) => k.toLowerCase() === typeNew.toLowerCase());
    if (found) {
      [, comp] = found;
    }

    return comp;
  };

  return getIcon(props.type);
};

export default IconSelector;
  • Usage
<Menu.Item key="1" icon={menu.icon ? <IconSelector type={menu.icon} /> : null}>
   Smile
</Menu>

Or

<Menu.Item key="1">
  <IconSelector type="smile" />
  <span>Smile</span>  
</Menu>

Upvotes: 1

Rikesh Lal Shrestha
Rikesh Lal Shrestha

Reputation: 111

I am using @loadable/component and by created a dynamic component that passes type

File DynamicIcon.js:

import loadable from "@loadable/component";

const DynamicIcon = loadable(props => 
import(`@ant-design/icons/es/icons/${props.type}.js`)
.catch(err => import(`@ant-design/icons/es/icons/WarningOutlined.js`)))

export default DynamicIcon;

And invoke the icon as before v3:

<DynamicIcon type={'TagOutlined'} />

Upvotes: 9

J&#243;zef Podlecki
J&#243;zef Podlecki

Reputation: 11283

That seems to work

const Icon = ({type, ...rest}) => {
  const icons = require(`@ant-design/icons`);
  const Component = icons[type];
  return <Component {...rest}/>
}

Upvotes: 4

Related Questions