Icons (아이콘)
Foundation은 Lucide React를 기본 아이콘 시스템으로 사용합니다.
아이콘 철학
Foundation의 아이콘 시스템은 다음 원칙을 따릅니다:
- Lucide Icons: 일관된 디자인과 높은 품질의 아이콘 세트
- SVG First: 해상도 독립적이고 크기 조절 가능
- Accessibility: 적절한 ARIA 속성과 대체 텍스트 제공
- Performance: Tree-shaking으로 사용하는 아이콘만 번들에 포함
Lucide React
설치
npm install lucide-react기본 사용법
import { Home, User, Settings } from "lucide-react";
export default function Example() {
return (
<div className="flex gap-md">
<Home size={24} />
<User size={24} />
<Settings size={24} />
</div>
);
}아이콘 크기
표준 크기
| Size | 픽셀 | 사용 사례 | Prop |
|---|---|---|---|
| xs | 16px | Inline Icon, Badge | size={16} |
| sm | 20px | Button Icon, Input Icon | size={20} |
| md | 24px | Navigation, Card (기본) | size={24} |
| lg | 32px | Feature Icon | size={32} |
| xl | 48px | Hero Icon | size={48} |
예제
import { Star } from 'lucide-react'
<Star size={16} className="text-yellow-500" /> {/* xs */}
<Star size={20} className="text-yellow-500" /> {/* sm */}
<Star size={24} className="text-yellow-500" /> {/* md */}
<Star size={32} className="text-yellow-500" /> {/* lg */}
<Star size={48} className="text-yellow-500" /> {/* xl */}아이콘 색상
Tailwind Color Classes
import { Heart } from 'lucide-react'
<Heart className="text-red-500" />
<Heart className="text-gray-400" />
<Heart className="text-primary" />상태별 색상
import { Bell } from 'lucide-react'
// Default
<Bell className="text-gray-600" />
// Hover
<button className="group">
<Bell className="text-gray-600 group-hover:text-primary" />
</button>
// Active
<Bell className="text-primary" />컴포넌트별 아이콘 가이드
Button with Icon
import { Download, ChevronRight } from 'lucide-react'
// Icon before text
<button className="flex items-center gap-sm px-md py-sm bg-primary text-white rounded">
<Download size={20} />
<span>Download</span>
</button>
// Icon after text
<button className="flex items-center gap-sm px-md py-sm bg-white border rounded">
<span>Next</span>
<ChevronRight size={20} />
</button>
// Icon only
<button className="p-sm bg-white border rounded">
<Download size={20} />
</button>Input with Icon
import { Search, Mail } from 'lucide-react'
// Left icon
<div className="relative">
<Search size={20} className="absolute left-md top-1/2 transform -translate-y-1/2 text-gray-400" />
<input className="pl-xl pr-md py-sm border rounded w-full" placeholder="Search..." />
</div>
// Right icon
<div className="relative">
<input className="pl-md pr-xl py-sm border rounded w-full" placeholder="Email" />
<Mail size={20} className="absolute right-md top-1/2 transform -translate-y-1/2 text-gray-400" />
</div>Navigation
import { Home, Users, Settings, LogOut } from "lucide-react";
export default function Navigation() {
return (
<nav className="flex flex-col gap-sm">
<a
href="#"
className="flex items-center gap-md px-md py-sm hover:bg-gray-100 rounded"
>
<Home size={20} />
<span>Home</span>
</a>
<a
href="#"
className="flex items-center gap-md px-md py-sm hover:bg-gray-100 rounded"
>
<Users size={20} />
<span>Users</span>
</a>
<a
href="#"
className="flex items-center gap-md px-md py-sm hover:bg-gray-100 rounded"
>
<Settings size={20} />
<span>Settings</span>
</a>
<a
href="#"
className="flex items-center gap-md px-md py-sm hover:bg-gray-100 rounded text-red-600"
>
<LogOut size={20} />
<span>Logout</span>
</a>
</nav>
);
}실전 예제
Feature Card
import { Zap, Shield, Gauge } from "lucide-react";
export default function Features() {
return (
<div className="grid grid-cols-1 md:grid-cols-3 gap-lg">
<div className="p-lg bg-white border rounded text-center">
<div className="inline-flex items-center justify-center w-16 h-16 bg-primary bg-opacity-10 rounded-full mb-md">
<Zap size={32} className="text-primary" />
</div>
<h3 className="text-xl font-semibold mb-sm">Fast</h3>
<p className="text-gray-600">Lightning fast performance</p>
</div>
<div className="p-lg bg-white border rounded text-center">
<div className="inline-flex items-center justify-center w-16 h-16 bg-green-100 rounded-full mb-md">
<Shield size={32} className="text-green-600" />
</div>
<h3 className="text-xl font-semibold mb-sm">Secure</h3>
<p className="text-gray-600">Enterprise-grade security</p>
</div>
<div className="p-lg bg-white border rounded text-center">
<div className="inline-flex items-center justify-center w-16 h-16 bg-blue-100 rounded-full mb-md">
<Gauge size={32} className="text-blue-600" />
</div>
<h3 className="text-xl font-semibold mb-sm">Reliable</h3>
<p className="text-gray-600">99.9% uptime guarantee</p>
</div>
</div>
);
}Alert with Icon
import { Info, AlertTriangle, CheckCircle, XCircle } from "lucide-react";
export default function Alerts() {
return (
<div className="space-y-md">
{/* Info */}
<div className="flex items-start gap-md p-md bg-blue-50 border-blue-200 border rounded">
<Info size={20} className="text-blue-600 mt-xs" />
<p className="text-blue-800">This is an informational message</p>
</div>
{/* Success */}
<div className="flex items-start gap-md p-md bg-green-50 border-green-200 border rounded">
<CheckCircle size={20} className="text-green-600 mt-xs" />
<p className="text-green-800">Operation completed successfully</p>
</div>
{/* Warning */}
<div className="flex items-start gap-md p-md bg-yellow-50 border-yellow-200 border rounded">
<AlertTriangle size={20} className="text-yellow-600 mt-xs" />
<p className="text-yellow-800">Please review before proceeding</p>
</div>
{/* Error */}
<div className="flex items-start gap-md p-md bg-red-50 border-red-200 border rounded">
<XCircle size={20} className="text-red-600 mt-xs" />
<p className="text-red-800">An error occurred</p>
</div>
</div>
);
}접근성 고려사항
ARIA Labels
의미를 전달하는 아이콘에는 aria-label을 추가하세요.
import { Trash2 } from "lucide-react";
<button aria-label="Delete item">
<Trash2 size={20} />
</button>;장식용 아이콘
장식용 아이콘에는 aria-hidden을 추가하세요.
import { Star } from "lucide-react";
<div>
<Star size={16} aria-hidden="true" className="text-yellow-500" />
<span>Featured</span>
</div>;다음 단계
Last updated on