Skip to content

Instantly share code, notes, and snippets.

@sanusart
Last active November 9, 2022 10:45
Show Gist options
  • Save sanusart/52311c413b10aa4f2c6cc29de8254f73 to your computer and use it in GitHub Desktop.
Save sanusart/52311c413b10aa4f2c6cc29de8254f73 to your computer and use it in GitHub Desktop.
Use custom icons in Antd v3 #antd #ant-design #icons #webpack

Ant design v3.9.0 custom svg icons and icons overrides

Why?

  • If you need to use material icons in your project for example.
  • If you need to add cusom icons

Preparations

File examples bellow

You will need to alias default icons path in a same way you would if addressing the bundle size issue

  • install svgson npm i -D svgson
  • create ./src/icons.js file in your project
  • Add the following to your webpack's resolve:
alias: {
  '@ant-design/icons/lib/dist$': path.resolve(__dirname, '../src/icons.js')
}
  • Create the fllowing file structure in the root of your project:
icons/
├── generate.js
└── svg
    ├── search.svg
    └── wc.svg
  • add npm script "generate:icons": "node ./icons/generate.js" to your package.json

Now place your icons in the svg directory

Running

From cmd run npm run generate:icons

This will generate usable icons in ./icons/icons directory your file structure should now be like this:

icons/
├── generate.js
├── icons
│   ├── SearchOutline.js <-- generated
│   └── WcOutline.js     <-- generated
└── svg
    ├── search.svg
    └── wc.svg

You are now can export this generated icons in the file we aliased erlier in webpack (the icons.js) and use them as if this icons came from Antd

svg file name used as name of the icon

for example using button as the following will give you 'wc' icon on the button:

<Button icon="ws">Take me to the restroom</Button>

How to use custom icon with <Icon/> component

Using custom (not overwritten) icons won't work as <Icon type="ws" />

Fortunatly Antd <Icon/> component provides a render prop so this will work <Icon component={ <WcIconComponnet/> } />

Icons name which are exists in Antd and being overwritten will work just fine. So using <Icon type="search" />, even if we performed override on it will work just fine as well.

Note that icons named with the same name as in Antd will override the originals. For example: search.svg exists in Antd so it will be overriten by yours, ws.svg is a custom one

/* eslint-disable @typescript-eslint/no-var-requires */
const fs = require('fs');
const path = require('path');
const { parse } = require('svgson');
const iconsDir = path.resolve(__dirname, `./icons`);
const svgDir = path.resolve(__dirname, `./svg`);
const upperFirst = (text) => text.charAt(0).toUpperCase() + text.slice(1);
const camelCase = (str) =>
str.toLowerCase().replace(/[^a-zA-Z0-9]+(.)/g, (m, chr) => chr.toUpperCase());
const iterateOverChildren = (children) =>
children.map((child) => ({
tag: child.name,
attrs: { ...child.attributes },
...(child.children ? iterateOverChildren(child.children) : null)
}));
const getSvgFileList = () => fs.readdirSync(svgDir).map((file) => file.replace('.svg', ''));
getSvgFileList().forEach((file) => {
fs.readFile(`${svgDir}/${file}.svg`, 'utf8', (err, data) => {
if (err) {
if (err.code === 'ENOENT') {
throw new Error(`\n\nMake sure icon file ${err.path} exists\n\n`);
}
}
parse(`${data}`).then((json) => {
const out = {
name: file,
theme: 'outline',
icon: {
tag: 'svg',
attrs: {
viewBox: json.attributes.viewBox,
width: json.attributes.width,
height: json.attributes.height
},
children: iterateOverChildren(json.children)
}
};
const fileName = upperFirst(`${camelCase(file)}Outline`);
const fileContent = `// ${fileName}.svg is auto generated, please do not edit manually\n'use strict';\nObject.defineProperty(exports, '__esModule', { value: true });\nconst ${fileName} = ${JSON.stringify(
out,
null,
2
)};
\nexports.default = ${fileName};`;
if (!fs.existsSync(iconsDir)) {
fs.mkdirSync(iconsDir);
}
fs.writeFile(`${iconsDir}/${fileName}.js`, fileContent, 'utf8', (err) => {
if (err) {
throw new Error(`Something went wrong during ${fileName}.js generation`);
}
});
console.log('\x1b[30m\x1b[42m', 'Generated ', '\x1b[0m', `${fileName}.svg`);
});
});
});
// The file used to override via webpack resolve of "@ant-design/icons/lib/dist"
export { default as WcOutline } from '../icons/icons/WcOutline';
export { default as SearchOutline } from '../icons/icons/SearchOutline';
// Regular exports of antd
export { default as LoadingOutline } from '@ant-design/icons/lib/outline/LoadingOutline';
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment