Reputation: 11
Basically, I'm using iconfiy with tailwind and addDynamicIconSelectors()
, where you are supposed to add icon as classes like this 'className = 'icon-[icon-name]''
, and I have a custom component that accepts that name of the class and adds it to a div with the above className.
The issue is: Tailwind is purging most (not all, for example 'mdi:heart' is working fine) classes and I see no icons, the icon component was already used many times in many components and pages and now I'm just updating it, since before I used the iconfity react component but it was causing a weird loading issue in next js where you see icons pop up, that's why I switched to Tailwind.
This is my component:
import { cn } from '@/lib/utils'
type IconI = {
name?: string
className?: string
width?: string | number
rotate?: number
hFlip?: boolean
vFlip?: boolean
} & React.InputHTMLAttributes<HTMLDivElement>
const Icon: React.FC<IconI> = ({
name,
className,
width,
rotate,
hFlip,
vFlip,
...props
}) => {
// replace : in names with --
const generateIconName = (name: string) => {
if (!name) return ''
const tempName = name.replace(/:/g, '--')
console.log(`Generated icon class: icon-[${tempName}]`)
return `icon-[${tempName}]`
}
return <span className={cn(generateIconName(name ?? ''), className)} />
}
export default Icon
I have been messing around with safelist and for example if I add 'mdi:tag'
directly to safe list the icon works, but if I add a pattern that excludes 'icon-['
for example, it doesn't, what is the best approach to take?
This is my Tailwind config
import type { Config } from 'tailwindcss'
const { addDynamicIconSelectors } = require('@iconify/tailwind')
const config = {
// mode: 'jit',
// purge: ['./public/**/*.html', './src/**/*.{js,jsx,ts,tsx,vue}'],
// content: [
// './app/**/*.{js,ts,jsx,tsx,mdx}', // Note the addition of the `app` directory.
// './pages/**/*.{js,ts,jsx,tsx,mdx}',
// './components/**/*.{js,ts,jsx,tsx,mdx}',
// // Or if using `src` directory:
// './src/**/*.{js,ts,jsx,tsx,mdx}',
// ],
// darkMode: 'class',
darkMode: ['class'],
content: [
'./pages/**/*.{ts,tsx}',
'./components/**/*.{ts,tsx}',
'./app/**/*.{ts,tsx}',
'./src/**/*.{ts,tsx}',
],
theme: {
container: {
center: true,
padding: {
DEFAULT: '15px',
sm: '15px',
lg: '15px',
xl: '0',
'2xl': '0',
},
screens: {
sm: '640px',
md: '768px',
lg: '1024px',
xl: '1280px',
'2xl': '1440px',
'3xl': '1600px',
},
},
extend: {
gridTemplateColumns: {
// 24 column grid
20: 'repeat(20, minmax(0, 1fr))',
},
screens: {
sm: '640px',
md: '768px',
lg: '1024px',
xl: '1280px',
'2xl': '1550px',
'3xl': '1800px',
},
fontSize: {
'heading-3xl': '5.5rem',
'heading-2xl': '4.5rem',
'heading-xl': '3.5rem',
'heading-lg': '2.5rem',
'heading-md': '2.25rem',
'heading-sm': '2rem',
'heading-xs': '1.75rem',
'heading-2xs': '1.5rem',
'heading-3xs': '1.25rem',
'paragraph-lg': '1rem',
'paragraph-md': '0.875rem',
'paragraph-sm': '0.75rem',
'paragraph-xs': '0.625rem',
s: '0.825rem',
'2xs': '0.625rem',
'3xs': '0.5rem',
},
colors: {
primary: '#072A1F',
secondary: '#000000',
danger: {
50: '#FFF7F7',
100: '#FEEFEF',
200: '#FCD6D7',
300: '#FABBBD',
400: '#F68B8D',
500: '#F1595C',
600: '#D75052',
700: '#913638',
800: '#6D292A',
900: '#461A1B',
},
black: {
50: '#F9FAFB',
100: '#F4F5F7',
200: '#E5E7EB',
300: '#D2D6DC',
400: '#9FA6B2',
500: '#111112',
600: '#475569',
700: '#334155',
800: '#1E293B',
900: '#0F172A',
},
warning: {
50: '#FFFAF8',
100: '#FFF4F1',
200: '#FEE4DA',
300: '#FDD2C3',
400: '#FCB298',
500: '#FA916B',
600: '#DF8260',
700: '#965741',
800: '#714231',
900: '#492B20',
},
blue: {
light: '#40DCFE',
},
cyan: {
primary: '#00FFF0',
},
info: {
50: '#F3FEFF',
100: '#E7FEFF',
200: '#C5FDFF',
300: '#A3FCFF',
400: '#5FF9FF',
500: '#0CE7FA',
600: '#00B8D4',
700: '#007A8D',
800: '#005E67',
900: '#003F42',
},
success: {
50: '#F3FEF8',
100: '#E7FDF1',
200: '#C5FBE3',
300: '#A3F9D5',
400: '#5FF5B1',
500: '#50C793',
600: '#3F9A7A',
700: '#2E6D61',
800: '#1F4B47',
900: '#0F2A2E',
},
gray: {
50: '#F9FAFB',
100: '#F4F5F7',
200: '#E5E7EB',
300: '#D2D6DC',
400: '#9FA6B2',
500: '#68768A',
600: '#475569',
700: '#334155',
800: '#1E293B',
900: '#0F172A',
primary: '#B4B4B4',
secondary: '#FCFCFC',
secondaryDark: '#F7F7F7',
light: '#F3F3F3',
lighter: '#F8F8F8',
},
red: {
secondary: '#FF114A',
secondaryLightest: '#FFF1F3',
},
orange: {
primary: '#FE852E',
},
purple: {
primary: '#5145DD',
},
yellow: {
primary: '#FDD60C',
},
pink: {
primary: '#FF1276',
},
green: {
primary: '#2FB98E',
primaryLight: '#45DD82',
secondary: '#072A1F',
},
},
fontFamily: {
inter: ['Inter', 'sans-serif'],
GilroyBold: ['var(--font-GilroyBold)', 'sans-serif'],
GilroyHeavy: ['var(--font-GilroyHeavy)', 'sans-serif'],
GilroyLight: ['var(--font-GilroyLight)', 'sans-serif'],
GilroyMedium: ['var(--font-GilroyMedium)', 'sans-serif'],
GilroyRegular: ['var(--font-GilroyRegular)', 'sans-serif'],
ChroniBlack: ['var(--font-ChroniBlack)', 'sans-serif'],
ChroniLight: ['var(--font-ChroniLight)', 'sans-serif'],
ChroniSemiBold: ['var(--font-ChroniSemiBold)', 'sans-serif'],
PetitFormal: ['var(--font-PetitFormal)', 'sans-serif'],
SyncoRegular: ['var(--font-SyncopateRegular)', 'sans-serif'],
SyncoBold: ['var(--font-SyncopateBold)', 'sans-serif'],
Montserrat: ['var(--font-MontserratFont)', 'sans-serif'],
MontserratBold: ['var(--font-MontserratBold)', 'sans-serif'],
MontserratSemiBold: ['var(--font-MontserratSemiBold)', 'sans-serif'],
MontserratMedium: ['var(--font-MontserratMedium)', 'sans-serif'],
// add weight to the array
MontserratRegular: ['var(--font-MontserratRegular)', 'sans-serif'],
MontserratLight: ['var(--font-MontserratLight)', 'sans-serif'],
},
boxShadow: {
base: '0px 0px 1px rgba(40, 41, 61, 0.08), 0px 0.5px 2px rgba(96, 97, 112, 0.16)',
base2:
'0px 2px 4px rgba(40, 41, 61, 0.04), 0px 8px 16px rgba(96, 97, 112, 0.16)',
base3: '16px 10px 40px rgba(15, 23, 42, 0.22)',
deep: '-2px 0px 8px rgba(0, 0, 0, 0.16)',
dropdown: '0px 4px 8px rgba(0, 0, 0, 0.08)',
testi: '0px 4px 24px rgba(0, 0, 0, 0.06)',
todo: 'rgba(235 233 241, 0.6) 0px 3px 10px 0px',
},
keyframes: {
zoom: {
'0%, 100%': { transform: 'scale(0.5)' },
'50%': { transform: 'scale(1)' },
},
tada: {
'0%': { transform: 'scale3d(1, 1, 1)' },
'10%, 20%': {
transform: 'scale3d(1, 1, 0.95) rotate3d(0, 0, 1, -10deg)',
},
'30%, 50%, 70%, 90%': {
transform: 'scale3d(1, 1, 1) rotate3d(0, 0, 1, 10deg)',
},
'40%, 60%, 80%': {
transform: 'rotate3d(0, 0, 1, -10deg)',
},
'100%': { transform: 'scale3d(1, 1, 1)' },
},
},
animation: {
'spin-slow': 'spin 3s linear infinite',
zoom: 'zoom 1s ease-in-out infinite',
tada: 'tada 1.5s ease-in-out infinite',
},
},
},
safelist: [
{
pattern: /^icon-\[.+\]$/,
}
],
plugins: [
require('tailwindcss-animate'),
addDynamicIconSelectors({
iconPrefix: 'icon-',
}),
],
} satisfies Config
export default config
Upvotes: 1
Views: 555
Reputation: 11
I believe this question is the same as this one?
You might just be having a problem with the regex. Try some javascript regex builder online and make sure your exact classes are matching the regex you provide? I used regexr to verify this one.
module.exports = {
safelist: [
{ pattern: /^icon-\[[a-z]{3}--[a-z-]+\]$/ },
// …
],
// …
}
This config will safe list classes such as icon-[mdi--heart]
and icon-[mdi--heart-big-solid]
but not icon-[mi--heart]
(because of the {3}
) or icon-[mdi--heart_solid]
(because of the _
).
But even better than the safe list IMO is to use the dictionary approach in that answer and have the desired classes all spelled out right there in the component, or else the next time someone edits the classes it might break again.
Upvotes: 0