Integrating Icon Components into Ant Design Vue Buttons and Building a Visual Icon Selector
This article explains how to extend Ant Design Vue's Button component with a custom icon prop, create a VpButton wrapper that preserves all original button features, and develop a visual icon selector that generates an icon list from public iconfont scripts for low‑code admin interfaces.
The article introduces a practical scenario where business requirements demand a button component that can display icons via a simple icon attribute instead of the default icon slot of Ant Design Vue's a-button . It outlines the limitations of the existing implementation and the need for a more convenient API.
To solve this, a new wrapper component VpButton is created. It merges the original a-button props with additional custom props such as ico , icoSize , icoColor , and primaryColor . Two approaches for prop forwarding are discussed: using v-bind="$attrs" (simple but non‑reactive) and explicitly listing all props (more verbose but fully reactive). The chosen solution extracts the original button props programmatically, combines them with the custom props, and passes only the relevant ones to a-button via a usePickedProps hook.
import buttonProps from 'ant-design-vue/es/button/buttonTypes'
import { initDefaultProps } from 'ant-design-vue/es/_util/props-util'
const _buttonProps = initDefaultProps(buttonProps(), { type: 'default' })
console.log(_buttonProps)Custom props are defined in enhancedProps and merged with the extracted button props to form the final props object for VpButton . The component renders the underlying Button with the merged props and conditionally inserts an IconSvg element when ico is provided.
export default defineComponent({
name: 'VpButton',
props: buttonProps,
setup(props, { slots }) {
const innerProps = usePickedProps(props, innerKeys)
return () => (
{props.ico && !props.loading ?
: null}
{slots?.default?.()}
)
},
})The article then explores extending the icon source to support both Ant Design icons and custom business icons via an icoSource prop. It explains why resolving Ant Design icons inside the wrapper requires global registration and demonstrates the use of resolveComponent and h for dynamic rendering.
Next, a visual icon selector is proposed for low‑code admin scenarios where users need to pick icons for menus. Two methods for obtaining an icon list are compared: manually maintaining an array versus scraping public iconfont resources. The chosen approach fetches the public JavaScript file that defines the SVG icons, extracts identifiers with the prefix vp-icon- using a regular expression, and writes the list to a JSON file.
import fs from "fs"
import axios from "axios"
const SVG_ICON_SCRIPT_URL = "https://at.alicdn.com/t/c/font_3736402_d50r1yq40hw.js"
const SVG_ICON_PREFIX = "vp-icon-"
function getIcons(str) {
const reg = new RegExp(`id="${SVG_ICON_PREFIX}([^\"]+)"`)
return str.match(/id="[^"]*"/g).map(item => item.replace(reg, "$1"))
}
export async function genIconListJson() {
const res = await axios.get(SVG_ICON_SCRIPT_URL)
if (res.status === 200) {
const iconList = getIcons(res.data)
fs.writeFile(new URL("../src/assets/json/icons.json", import.meta.url), JSON.stringify(iconList, null, 2), err => {
if (err) console.error(err)
else console.log("Icon list written successfully!")
})
}
}
genIconListJson()Finally, the article summarizes that the wrapper component preserves all original button capabilities while adding convenient icon handling, and the icon selector provides a user‑friendly way to browse and choose icons, encouraging developers to adopt this pattern for building extensible UI component libraries.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.