Use any icons with Pure CSS in CSS Panda. 'Twas Inspired by @unocss/preset-icons
npm i -D @css-picons/config @iconify-json/[the-collection-you-want]
We use Iconify as our data source of icons. You need to install the corresponding iconset in
devDependencies
by following the @iconify-json/*
pattern. For example, @iconify-json/mdi
for
Material Design Icons, @iconify-json/tabler
for
Tabler. You can refer to Icรดnes or
Iconify for all the collections available.
If you prefer to install the all the icon sets available on Iconify at once (~130MB):
npm i -D @iconify/json
Even if you do this, only the ones used in your code will be packaged by panda. That's nice.
In your panda.config.*
file, import cssPicons
from @css-picons/config
, then add it to presets
import { cssPicons } from '@css-picons/config'
export default defineConfig({
presets: [
// ...
cssPicons({
// Specify all the icon sets you'll be using
collections: ['mdi'],
}),
],
})
Then make sure your theme
is extendable, if you have configured it.
// panda.config.*
export default defineConfig({
//...
theme: {
extend: {
// ...
},
},
})
Now you can use it in your components in all the ways css-panda
allows through the icon
recipe which is exported
from your design system. The icon name follows the format <collection>:<name>
import { icon } from '../panda/recipes'
return (
<div
className={cx(
icon({ name: 'mdi:emoticon-happy' }),
css({
color: 'yellow.500',
fontSize: '6xl',
}),
)}
/>
)
Result:
// A basic anchor icon from Phosphor icons
const className = icon({ name: 'ph:anchor-simple-thin' })
// An orange alarm from Material Design Icons
const className = cx(icon({ name: 'mdi:alarm' }), css({ color: 'orange.400' }))
// A large react logo
const className = cx(icon({ name: 'logos:react' }), css({ fontSize: '3xl' }))
// Sun in light mode, Moon in dark mode, from Carbon
const className = icon({ name: { base: 'carbon:sun', _dark: 'carbon:moon' } })
// Twemoji of laugh, turns to tear on hovering
const className = icon({
name: {
base: 'twemoji:grinning-face-with-smiling-eyes',
_hover: 'twemoji:face-with-tears-of-joy',
},
})
When using in jsx
you might want to use it in a reusable component, in such cases you have to tell css-panda
the
name of the component so it can watch it when generating styles. An example:
function AppIcon(props: IconVariants) {
return (
<div
className={cx(
icon(props),
css({
fontSize: '6xl',
}),
)}
/>
)
}
// Somewhere else
return <AppIcon name="mdi:emoticon-happy" />
You tell panda
to watch the external component by using the jsx
key in the config.
import { cssPicons } from '@css-picons/config'
export default defineConfig({
presets: [
// ...
cssPicons({
// ...
jsx: 'AppIcon',
}),
],
})
Note: Panda automatically tracks components named as the capitalized version of the identifier. e.g. If your
identifier is daocons, a component called Daocons
that consumes it will be automatically tracked. In this case, we
automatically track components named Icon
.
By default, you export icon
from recipes which is then consumed to render the icons. But you can change this in the
config with the identifier
key.
import { cssPicons } from '@css-picons/config'
export default defineConfig({
presets: [
// ...
cssPicons({
// ...
identifier: 'cssIcon',
}),
],
})
Then export and use the new identifier in your project instead.
import { cssIcon } from '../panda/recipes'
return (
<div
className={cx(
cssIcon({ name: 'mdi:emoticon-happy' }),
css({
color: 'yellow.500',
fontSize: '6xl',
}),
)}
/>
)
You can provide extra styles to control the default behavior of the icons. You could make icons vertically aligned and inline by default by the following example:
import { cssPicons } from '@css-picons/config'
export default defineConfig({
presets: [
// ...
cssPicons({
// ...
styles: {
verticalAlign: 'middle',
display: 'inline-block',
},
}),
],
})
By default, css-picons
will choose the rendering modes automatically for each icon based on the icons'
characteristics. You can read more in this blog post. In some cases, you may
want to explicitly set the rendering modes for each icon.
?bg
forbackground-img
- renders the icon as a background image?mask
formask
- renders the icon as a mask image
For example, vscode-icons:file-type-light-pnpm
, an icon with colors (the svg
doesn't contain currentColor
) that
will be rendered as a background image. Use vscode-icons:file-type-light-pnpm?mask
to render it as a mask image and
bypass it's colors.
You can also set the default mode in your config with the mode
key. It's auto
by default which means css-picons
automatically selects a mode based on it's perception of the icon.
export default defineConfig({
presets: [
// ...
cssPicons({
// ...
mode: 'mask',
}),
],
})
You can also provide your own custom collections by passing a tuple.
The first item in the tuple is the collection's name.
The second can either be a function or an object.
Basic example
export default defineConfig({
presets: [
// ...
cssPicons({
// ...
collections: [
// ...
[
'custom',
{
circle: '<svg viewBox="0 0 120 120"><circle cx="60" cy="60" r="50"></circle></svg>',
},
],
],
}),
],
})
Then use it through the custom
icon name:
import { icon } from '../panda/recipes'
return <div className={icon({ name: 'custom:circle' })} />
You can also provide a function that resolves to a string:
Read from file
export default defineConfig({
presets: [
// ...
cssPicons({
// ...
collections: [
// ...
[
'custom',
{
vite: () => fs.readFile('./public/vite.svg', 'utf-8'),
},
],
],
}),
],
})
Usage:
import { icon } from '../panda/recipes'
return <div className={icon({ name: 'custom:vite' })} />
Fetch icon svg from a remote server
// Native fetch is not defined in the node process
import fetch from 'node-fetch'
export default defineConfig({
presets: [
// ...
cssPicons({
// ...
collections: [
// ...
[
'solar',
{
'airbuds-outline': async () => {
return await fetch('https://api.iconify.design/solar:airbuds-outline.svg?color=%23888888').then((res) =>
res.text(),
)
},
},
],
],
}),
],
})
Usage:
import { icon } from '../panda/recipes'
return <div className={icon({ name: 'solar:airbuds-outline' })} />
Iconify JSON or function returning iconify JSON
import feIconsData from '@iconify-json/fe/icons.json'
import phIconsData from '@iconify-json/ph/icons.json'
export default defineConfig({
presets: [
// ...
cssPicons({
// ...
collections: [
// ...
['fe', feIconsData],
['ph', () => phIconsData],
],
}),
],
})
Usage:
import { icon } from '../panda/recipes'
return <div className={icon({ name: 'fe:check-verified' })} />
return <div className={icon({ name: 'ph:alien' })} />
Dynamic import
export default defineConfig({
presets: [
// ...
cssPicons({
// ...
collections: [
// ...
['carbon', () => import('@iconify-json/carbon/icons.json').then((i) => i.default as any)],
],
}),
],
})
Usage:
import { icon } from '../panda/recipes'
return <div className={icon({ name: 'carbon:build-tool' })} />
Fetch icons data from a remote server
// Native fetch is not defined in the node process
export default defineConfig({
presets: [
// ...
cssPicons({
// ...
collections: [
// ...
[
'circle-flags',
async () => {
//* fetch iconifyJson from a remote server:
//! We use node-fetch package because we can't access the native fetch
return await fetch(
'https://raw.githubusercontent.com/iconify/icon-sets/master/json/circle-flags.json',
).then((res) => res.json())
},
],
],
}),
],
})
Usage:
import { icon } from '../panda/recipes'
return <div className={icon({ name: 'circle-flags:ng' })} />
We provide a transform method which lets you transform icons when loading, for example adding fill attribute with currentColor.
export default defineConfig({
presets: [
// ...
cssPicons({
// ...
transform(svg) {
return svg.replace(/#fff/, 'currentColor')
},
}),
],
})
We also provide the collection
and icon
so you can streamline your transformations.
export default defineConfig({
presets: [
// ...
cssPicons({
// ...
transform(svg) {
// do not apply fill to this icons on this collection
if (collection === 'custom' && icon === 'circle') return svg
return svg.replace(/#fff/, 'currentColor')
},
}),
],
})