ReactのアイコンライブラリとしてLucideを利用する

## はじめに
自作のアイコンはもちろん、[Material Design](https://fonts.google.com/icons)や[Font Awesome](https://fontawesome.com/icons)のアイコンをsvgファイルとしてコピーしたり、[React Icon](https://react-icons.github.io/react-icons/)や[Material UIのMaterial Icon](https://mui.com/material-ui/material-icons/)のようなライブラリを通してコンポーネントとして利用するなど、ReactでIconを利用する方法はさまざまです。

この記事ではそんなReactでIconを利用する方法の1つである、[Lucide](https://lucide.dev/)を紹介します。

## Lucide
Lucideはアイコンやシンボルを表示するためにsvgを提供するOSSライブラリです。この記事ではReactにおける活用を紹介しますが、Vanilla JSはもちろん、Vue、Svelte、Solid、React Native、Angular、Preactなどさまざまなケースに対応しています。

アイコンは多様で、執筆現在で1917個ものアイコンが用意されています。骸骨のアイコンもあるくらいなので、ほとんどのケースで欲しいアイコンがここから見つかると思います(最近はここから使えそうなアイコンを物色するくらいです)。
![スクリーンショット 2024-12-15 13.02.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591069/15496e97-d360-1154-1566-f9661db95337.png)
Webページから[アイコンの一覧](https://lucide.dev/icons/)を見ることができます。svgの`color`、`storoke-width`、`size`を一度に調整する機能やアイコンの検索機能が備わっており不自由なくアイコンの海を泳げます。

### Reactアプリケーションに導入する
実際にReactのアプリケーションにLucideを取り入れる方法を紹介します。
```command
pnpm i lucide-react
```

ライブラリのインストールが終了したら準備完了です。通常のIconであれば`lucide-react`からインポートしてそのまま使えます。
```tsx
import { Squirrel } from 'lucide-react';

export const Sample = () => {
  return <Squirrel color="#50e2d2" size={48} />;
};
```

https://codesandbox.io/embed/lkqqsg?view=editor+%2B+preview&module=%2Fsrc%2FApp.tsx

インポートしたコンポーネントには通常のsvgに渡せるpropsのほかに、追加して`size`、`color`、`strokeWidth`、`absoluteStrokeWidth`を渡せます。
`size`はアイコンの大きさで、デフォルトは`24`です。渡した数値pxで表示されます。
```tsx
// 48pxのリスのアイコン
<Squirrel color="#50e2d2" size={48} />
```
`color`は`stroke`の色を指定します。デフォルトは`currentColor`です。`svg`の`color`属性には追加されないので注意しましょう。

```tsx
// 輪郭が#50e2d2のリスのアイコン
<Squirrel color="#50e2d2" size={48} />
```

`strokeWidth`は輪郭の大きさです。デフォルトは`2`です。
```tsx
// 輪郭が3のリスのアイコン
<Squirrel color="#50e2d2" size={48} strokeWidth={3} />
```

`absoluteStrokeWidth`は`strokeWidth`を元に`stroke-width`属性を決めます。
デフォルトは`false`で、`strokeWidth`のまま`stroke-width`属性に値を渡します。
`true`にしたときは`strokeWidth`に`24`掛けたものを`size`で割った値になります。

https://codesandbox.io/embed/zg4z54?view=editor+%2B+preview

### lucide-lab
Lucideには調査中のアイコンがあります。
```command
pnpm i @lucide/lab
```
追加のインストールを行い、`Icon`コンポーネントの`iconNode`に`@lucide/lab`から取ってきたアイコンを渡します。
```tsx
import { Icon } from "lucide-react";
import { avocado } from "@lucide/lab";

export const Sample = () => {
  return (
    <>
      <Icon iconNode={avocado} color="#50e2d2" size={48} />
    </>
  );
};
```

https://codesandbox.io/embed/7rkktl?view=editor+%2B+preview&module=%2Fsrc%2FApp.tsx

### 塗りつぶす
アイコンの塗りつぶしは完全にサポートされていません。`fill`属性を付与してアイコンを塗りつぶした状態にします。

```tsx
import { Squirrel } from "lucide-react";

export const Sample = () => {
  return <Squirrel fill="#50e2d2" color="#50e2d2" size={48} />;
};
```

https://codesandbox.io/embed/fhcscj?view=editor+%2B+preview&module=%2Fsrc%2FApp.tsx

### アクセシビリティ
アイコンがテキストの補足のためであればそのままで良いですが、アイコンが単体で意味を持っている場合はアクセシブルな名前を付与する必要があります。名前は`aria-label`を通して付与します。
```tsx
import { Squirrel } from "lucide-react";

export const Sample = () => {
  return (
    <button>
      <Squirrel aria-label="リス" color="#50e2d2" size={48} />
    </button>
  );
};
```

https://codesandbox.io/embed/ppq4vq?view=editor+%2B+preview

一般的に`aria-label`でラベルを付与することは、完璧な対応とは言えません。[tailwindcssのsr-only](https://tailwindcss.com/docs/screen-readers#screen-reader-only-elements)のような実装が可能であればそちらを利用するようにしてください。

### 他の名前
これまで`lucide-react`からアイコンを意味する単語をそのままの名前でインポートしてきました。そのままの名前の場合既存のコンポーネントと名前が衝突してどちらかの名前を変更する必要が出てきます(`Edit`とか`Home`とか)。`lucide-react`ではそのままの名前の他に、suffixに`Icon`がついたものとprefixに`Lucide`がついた同一のアイコンが提供されています。
```tsx
import { Squirrel, SquirrelIcon, LucideSquirrel } from "lucide-react";

export const Sample = () => {
  return (
    <>
      <Squirrel color="#50e2d2" size={48} />
      <SquirrelIcon color="#50e2d2" size={48} />
      <LucideSquirrel color="#50e2d2" size={48} />
    </>
  );
};
```

https://codesandbox.io/embed/965lx9?view=editor+%2B+preview&module=%2Fsrc%2FApp.tsx

利用する名前を1種類にする制約を課したい場合は`lucide.d.ts`のようなものを作って`tsconfig.ts`に渡します。
```ts
// prefixだけ
declare module "lucide-react" {
  export * from "lucide-react/dist/lucide-react.prefixed";
}

// suffixだけ
declare module "lucide-react" {
  export * from "lucide-react/dist/lucide-react.suffixed";
}
```
そのままの名前だけにする方法は今のところないようです。

## おわりに
私はLucideのアイコンが豊富で捜索しやすい点を特に気に入っています。ライブラリとして利用する時も不便を感じることなく利用できるので、デザイン上でアイコンの見た目の制約がない場合は利用してみてはいかがでしょうか。とてもおすすめです。