The Skills component displays technical proficiencies through animated icons arranged in a flexible grid layout.
Overview
Key features:
- Animated icon grid with staggered entrance
- Hover effects with scale transformation
- Circular icon containers with gradient backgrounds
- Responsive grid that adapts to screen size
- Dark mode support
Component Structure
import React from 'react'
import { motion } from 'framer-motion'
import { techStack } from '@/constants'
import { styles } from '@/styles'
import { SectionWrapper } from '@/hooks'
function Skills() {
return (
<div className='bg-white/50 dark:bg-zinc-950/30
backdrop-blur-sm py-16 transition-colors duration-300'>
<div className="text-center mb-12">
<p className={`${styles.sectionSubText}
text-navy-600 dark:text-slate-400`}>
Technical Proficiency
</p>
<h2 className={`${styles.sectionHeadText}
text-navy-900 dark:text-slate-100`}>
Skills.
</h2>
</div>
<div className='flex justify-center lg:px-40 md:px-12 px-14 pb-8'>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
className='flex flex-wrap justify-center gap-8 max-w-7xl'
>
{techStack.map((skill, index) => (
<motion.div
className='aspect-square w-[85px] h-[85px]
bg-white/90 dark:bg-slate-800/90 rounded-full
flex items-center justify-center backdrop-blur-sm
hover:bg-navy-50 dark:hover:bg-slate-700
transition-colors group shadow-lg
border border-navy-200 dark:border-slate-600
hover:border-navy-400 dark:hover:border-slate-500'
key={skill.name}
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 1.5, delay: index * 0.15 }}
whileHover={{ scale: 1.1 }}
>
<img
src={skill.imageUrl}
alt={skill.name}
className='w-14 h-14 object-contain
group-hover:scale-110 transition-transform'
/>
</motion.div>
))}
</motion.div>
</div>
</div>
)
}
export default SectionWrapper(Skills, "skills");
Skill Icon Design
Each skill is displayed in a circular container:
<motion.div
className='aspect-square w-[85px] h-[85px]
bg-white/90 dark:bg-slate-800/90 rounded-full
flex items-center justify-center backdrop-blur-sm
hover:bg-navy-50 dark:hover:bg-slate-700
transition-colors group shadow-lg
border border-navy-200 dark:border-slate-600
hover:border-navy-400 dark:hover:border-slate-500'
key={skill.name}
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 1.5, delay: index * 0.15 }}
whileHover={{ scale: 1.1 }}
>
<img
src={skill.imageUrl}
alt={skill.name}
className='w-14 h-14 object-contain
group-hover:scale-110 transition-transform'
/>
</motion.div>
The icons animate in with a staggered 0.15s delay between each, creating a wave effect.
Animation Breakdown
Container Animation
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
Individual Icon Animation
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
transition={{ duration: 1.5, delay: index * 0.15 }}
Hover Effects
whileHover={{ scale: 1.1 }}
// Icon scales even more on hover
group-hover:scale-110
Tech Stack Data Structure
Define your tech stack in constants.js:
export const techStack = [
{
name: "React",
imageUrl: "/tech/react.png"
},
{
name: "Node.js",
imageUrl: "/tech/nodejs.png"
},
{
name: "MongoDB",
imageUrl: "/tech/mongodb.png"
},
{
name: "Express",
imageUrl: "/tech/express.png"
},
{
name: "JavaScript",
imageUrl: "/tech/javascript.png"
},
{
name: "TypeScript",
imageUrl: "/tech/typescript.png"
},
{
name: "Tailwind CSS",
imageUrl: "/tech/tailwind.png"
},
{
name: "Git",
imageUrl: "/tech/git.png"
},
// Add more skills...
];
Ensure skill images are square (1:1 aspect ratio) for best results.
Responsive Padding
Padding adjusts based on screen size:
Grid Behavior
The flex-wrap layout automatically adjusts:
<div className='flex flex-wrap justify-center gap-8 max-w-7xl'>
{/* Skills */}
</div>
- Icons wrap to new rows as needed
- 8 unit gap between items
- Maximum width of 7xl
- Center aligned
Icon Container Styling
Default State
- 85x85px circular container
- White/slate background with transparency
- Subtle shadow
- Navy/slate border
Hover State
- Scales to 110% (container)
- Icon scales to 110% (nested)
- Border color intensifies
- Background color changes
Dark Mode Comparison
bg-white/90
text-navy-600
border-navy-200
hover:bg-navy-50
hover:border-navy-400
Section Styles
The component uses predefined styles from styles.js:
styles.sectionSubText // "Technical Proficiency"
styles.sectionHeadText // "Skills."
Typical definitions:
export const styles = {
sectionSubText: "text-sm uppercase tracking-wider mb-3 font-semibold",
sectionHeadText: "text-4xl md:text-5xl lg:text-6xl font-black mb-6",
};
Performance Considerations
- Uses
transform for animations (GPU accelerated)
- Staggered animations prevent layout shift
backdrop-blur-sm provides subtle depth
- Image lazy loading recommended for many icons
Customization Options
Adjust Icon Size
w-[85px] h-[85px] // Container
w-14 h-14 // Icon
Change Animation Duration
transition={{ duration: 1.5, delay: index * 0.15 }}
Modify Gap Between Icons
gap-8 // Change to gap-6, gap-10, etc.