はじめに
フロントエンド開発でアイコンライブラリを選ぶとき、正直なところ選択肢が多すぎて迷いますよね。Font Awesome、Material Icons、Heroicons...どれも良いんですが、個人的にここ最近はLucide一択になってきました。
Lucideは、あの人気だったFeather Iconsのフォークから生まれたコミュニティ主導のアイコンライブラリです。現在はGitHubで20,000スター、月間6,200万ダウンロードという規模にまで成長しています。Feather Iconsが更新停滞気味だったところを、コミュニティが引き継いで発展させた形ですね。
とはいえ、説明を読むより実際に動かした方が早いと思います。size(サイズ)やcolor(色)、strokeWidth(線の太さ)を変えるとLucideのアイコンがどう変化するか、先に試してみたい方はこちらからどうぞ。
特徴・メリット
1,600以上のアイコンを網羅
執筆時点で1,655個のアイコンが利用可能です。一般的なUIパーツから、SNS系、ファイル操作、天気、デバイスなど、だいたい必要なものは揃っています。これ、意外と重要で、途中で「このアイコンがない」ってなると別のライブラリを追加する羽目になるんですよね。
軽量でツリーシェーキング対応
ここが個人的に推しポイントです。使うアイコンだけをインポートできるので、バンドルサイズが無駄に膨らまない。Font Awesomeのように「とりあえず全部入り」ではないので、パフォーマンスを気にするプロジェクトでも安心して導入できます。
主要フレームワーク全対応
対応しているフレームワークがかなり幅広いです。
- React / React Native
- Vue 3
- Svelte
- Angular
- Solid
- Preact
- Astro
- Flutter
各フレームワーク専用のパッケージが用意されているので、それぞれの作法に沿った形で使えます。
柔軟なカスタマイズ
色、サイズ、ストローク幅などをpropsで簡単に変更できます。Tailwind CSSとの相性も良くて、className経由でスタイリングできるのが地味に便利ですね。
一貫したデザイン
厳密なデザインルールに基づいて作られているので、どのアイコンを使っても統一感があります。24×24pxベース、2pxストローク、丸みを帯びたエッジという共通ルールが守られています。
インストール方法
使用するフレームワークに応じたパッケージをインストールします。
React
npm install lucide-react
# または
yarn add lucide-react
# または
pnpm add lucide-react
Vue 3
npm install lucide-vue-next
Svelte
npm install lucide-svelte
バニラJavaScript
npm install lucide
Lucideのサンプルを動かす
まずは実際に手を動かしてlucide-reactの挙動を確かめてみましょう。以下はハートアイコンのsize・color・strokeWidthという3つのpropsをスライダーとカラーピッカーでリアルタイムに変更できるサンプルです。Lucideのアイコンコンポーネントは、これらのpropsを渡すだけで見た目を自在に調整できます。
要点だけを抜き出すと、こういう書き方になります。
import { Heart } from 'lucide-react'
function App() {
const [size, setSize] = useState(48)
const [color, setColor] = useState('#ef4444')
const [strokeWidth, setStrokeWidth] = useState(2)
return (
<>
<Heart size={size} color={color} strokeWidth={strokeWidth} />
<input
type="range" min={16} max={120} value={size}
onChange={(e) => setSize(Number(e.target.value))}
/>
</>
)
}
実際に動かせるのが下のサンプルです。スライダーやカラーピッカーを操作すると、その場でハートアイコンの見た目が変わります。
スライダーでstrokeWidthを0.5まで下げると輪郭が繊細な線画風になり、4まで上げると太い縁取りのアイコンになります。colorを変えると塗りつぶしではなくstroke(線)の色が変わる点にも注目してください。Lucideのアイコンはデフォルトでfillなしの線画(アウトライン)スタイルなので、colorプロパティは輪郭線の色として反映されます。
基本的な使い方
Reactでの使用例
import { Home, Settings, User, Search } from 'lucide-react';
function App() {
return (
<div className="flex gap-4">
<Home size={24} color="#333" />
<Settings size={24} strokeWidth={1.5} />
<User className="text-blue-500" />
<Search className="w-6 h-6" />
</div>
);
}
コンポーネントとしてインポートして、そのまま使えます。propsでサイズや色を指定できますし、Tailwind CSSのクラスをそのまま渡すこともできます。
Vue 3での使用例
<script setup>
import { Home, Settings, User } from 'lucide-vue-next';
</script>
<template>
<div class="flex gap-4">
<Home :size="24" color="#333" />
<Settings :size="24" :stroke-width="1.5" />
<User class="text-blue-500" />
</div>
</template>
Vue版も同じような感覚で使えます。propsの渡し方がVue流になるだけですね。
動的にアイコンを切り替える
import { icons } from 'lucide-react';
function DynamicIcon({ name, ...props }) {
const Icon = icons[name];
if (!Icon) return null;
return <Icon {...props} />;
}
// 使用例
<DynamicIcon name="Home" size={24} />
<DynamicIcon name="Settings" size={24} />
アイコン名を文字列で指定したい場合は、iconsオブジェクトから動的に取得できます。CMSからアイコン名を取得するケースなんかで便利です。
実践的なユースケース
ナビゲーションメニュー
import { Home, FolderOpen, Users, Settings, LogOut } from 'lucide-react';
const menuItems = [
{ icon: Home, label: 'ホーム', href: '/' },
{ icon: FolderOpen, label: 'プロジェクト', href: '/projects' },
{ icon: Users, label: 'チーム', href: '/team' },
{ icon: Settings, label: '設定', href: '/settings' },
];
function Sidebar() {
return (
<nav className="w-64 bg-gray-800 text-white p-4">
<ul className="space-y-2">
{menuItems.map((item) => (
<li key={item.href}>
<a
href={item.href}
className="flex items-center gap-3 px-3 py-2 rounded hover:bg-gray-700"
>
<item.icon size={20} />
<span>{item.label}</span>
</a>
</li>
))}
</ul>
<button className="flex items-center gap-3 px-3 py-2 mt-4 text-red-400 hover:bg-gray-700 rounded w-full">
<LogOut size={20} />
<span>ログアウト</span>
</button>
</nav>
);
}
ボタンコンポーネント
import { Loader2 } from 'lucide-react';
function Button({ children, icon: Icon, loading, ...props }) {
return (
<button
className="flex items-center gap-2 px-4 py-2 bg-blue-500 text-white rounded disabled:opacity-50"
disabled={loading}
{...props}
>
{loading ? (
<Loader2 size={16} className="animate-spin" />
) : Icon ? (
<Icon size={16} />
) : null}
{children}
</button>
);
}
ローディング状態のスピナーにも使えます。animate-spinクラスと組み合わせるだけで回転するローディングアイコンの完成です。
入力フィールド
import { Search, X } from 'lucide-react';
function SearchInput({ value, onChange, onClear }) {
return (
<div className="relative">
<Search
size={18}
className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400"
/>
<input
type="text"
value={value}
onChange={onChange}
placeholder="検索..."
className="w-full pl-10 pr-10 py-2 border rounded focus:ring-2 focus:ring-blue-500"
/>
{value && (
<button
onClick={onClear}
className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600"
>
<X size={18} />
</button>
)}
</div>
);
}
検索ボックスのようなUIでも、アイコンを配置するだけで一気に見栄えが良くなります。
strokeWidthで選択状態を表現する
strokeWidthはアイコンの太さを変えるだけのpropsですが、ナビゲーションの選択状態を表現するのにも使えます。選択中のタブだけstrokeWidthを太くして色も変えると、テキストを増やさなくても「今どこにいるか」が伝わるUIになります。
function NavIcon({ icon: Icon, active }) {
return (
<Icon
size={22}
strokeWidth={active ? 2.5 : 1.5}
color={active ? '#2563eb' : '#9ca3af'}
/>
)
}
タブをクリックするとLucideのアイコンのstrokeWidthとcolorが切り替わる様子を、下のサンプルで確かめられます。
タブを切り替えるたびに、選択中のアイコンだけstrokeWidthが1.5から2.5へ太くなり、colorも青に変わっているはずです。strokeWidthの差を1.5と2.5ではなく1と3のように広げると、選択状態の主張がさらに強くなります。
Reactコンポーネントとしてアイコン付きボタンを作る
Lucideのアイコンは通常のReactコンポーネントなので、propsとして他のコンポーネントに渡して合成できます。ここでは送信ボタンの状態(待機中・送信中・成功・失敗)に応じて、表示するLucideアイコンをLoader2・CheckCircle2・XCircleで自動的に切り替えるボタンを作ります。
function StatusButton({ status }) {
if (status === 'loading') return <Loader2 className="animate-spin" />
if (status === 'success') return <CheckCircle2 color="#16a34a" />
if (status === 'error') return <XCircle color="#dc2626" />
return null
}
実際に送信ボタンを押すと、ローディング用のLoader2が回転し、その後ランダムに成功・失敗のアイコンへ切り替わるのが下のサンプルです。
「送信する」ボタンを押すとLoader2が回転し、1.2秒後にCheckCircle2(成功)かXCircle(失敗)のどちらかへランダムに切り替わります。Math.random() > 0.5の閾値を変えれば、失敗するケースを増やしてXCircle側の見た目を確認しやすくできます。
動的にアイコンを切り替える(動かして確認)
先ほどの「基本的な使い方」で紹介したiconsオブジェクトは、アイコン名を文字列で受け取って動的にコンポーネントを取得できます。ここではセレクトボックスで選んだ名前をもとに、Lucideのアイコンを実際に切り替えてみます。
import { icons } from 'lucide-react'
function DynamicIcon({ name }) {
const Icon = icons[name]
return Icon ? <Icon size={32} /> : null
}
セレクトボックスの選択肢を変えると、iconsオブジェクトから取得したLucideのアイコンがその場で切り替わります。
セレクトボックスでHeartやStarを選ぶと、CMSやAPIから受け取った文字列だけでアイコンを出し分けられることが分かります。iconNamesの配列にLucideの他のアイコン名(例えばTrash2やDownload)を追加すれば、選べるアイコンをそのまま増やせます。
まとめ
Lucideは、Feather Iconsの良さを引き継ぎつつ、コミュニティの力で大きく発展したアイコンライブラリです。
- 1,600以上のアイコンで大抵のケースをカバー
- ツリーシェーキング対応で軽量
- React、Vue、Svelteなど主要フレームワーク全対応
- 一貫したデザインで統一感のあるUI
- propsやクラスで柔軟にカスタマイズ可能
30代になって思うのは、ライブラリ選びは「枯れてるかどうか」より「活発にメンテされてるかどうか」が大事だということ。Lucideは月間6,000万以上のダウンロード、278人以上のコントリビューター、そして日々更新されるアイコンという形で、その活発さを証明しています。
アイコンライブラリで迷っているなら、まずLucideを試してみてください。時短にもなるし、QOLも上がりますよ。